试图从 2 个正在加入的子查询中获取一列并且分组不起作用

Posted

技术标签:

【中文标题】试图从 2 个正在加入的子查询中获取一列并且分组不起作用【英文标题】:Trying to grab a column from 2 subqueries being joined and grouping not working 【发布时间】:2021-03-29 09:19:07 【问题描述】:

我的表格是什么样子的:

mysql> select * from customer limit 3;
+-------------+---------------+-----------------------+------+--------+-------------+-------+
| customer_id | customer_name | profession            | age  | salary | town        | state |
+-------------+---------------+-----------------------+------+--------+-------------+-------+
|           1 | Julio Sperski | Architect             |   70 |  52016 | Conroe      | TX    |
|           2 | Micah Inchley | Biological  scientist |   86 |  45355 | Omaha       | NE    |
|           3 | Brigg Denny   | Chemist               |   80 |  21754 | Bakersfield | CA    |
+-------------+---------------+-----------------------+------+--------+-------------+-------+
3 rows in set (0.00 sec)

mysql> select * from vehicle limit 3;
+------------+---------------+--------------------+--------+--------+---------+----------------+--------------------+-----------------------+
| vehicle_id | vehicle_plate | registration_state | color  | make   | model   | vehicle_type   | per_day_rental_fee | per_day_insurance_fee |
+------------+---------------+--------------------+--------+--------+---------+----------------+--------------------+-----------------------+
|          1 | W9FLYC7       | TX                 | black  | toyota | cruiser | mid size sedan |                 44 |                    27 |
|          2 | CA1CJIZ       | NE                 | silver | ford   | se      | suv            |                 96 |                    71 |
|          3 | HB5YI9A       | CA                 | silver | dodge  | mpv     | truck          |                 26 |                    28 |
+------------+---------------+--------------------+--------+--------+---------+----------------+--------------------+-----------------------+
3 rows in set (0.00 sec)

mysql> select * from rental limit 3;
+-----------+-------------+------------+-------------------+--------------------+-------------------------+----------------------------+
| rental_id | customer_id | vehicle_id | start_rental_date | return_rental_date | per_day_rental_fee_paid | per_day_insurance_fee_paid |
+-----------+-------------+------------+-------------------+--------------------+-------------------------+----------------------------+
|         1 |          32 |          4 | 3/4/2019          | 3/6/2019           | no                      | no                         |
|         2 |          42 |         39 | 3/23/2019         | 3/24/2019          | yes                     | yes                        |
|         3 |          33 |         14 | 10/18/2020        | 10/24/2020         | no                      | no                         |
+-----------+-------------+------------+-------------------+--------------------+-------------------------+----------------------------+
3 rows in set (0.00 sec)

customer_id、vehicle_id 和 rent_id 是主键。

customer_id 和 vehicle_id 是分别指向客户和车辆表的外键。

所以我试图抓取第三列并显示它。 查询大致如下:

对于租车公司运营的每个注册州,从某个客户州返回最多的客户。就像如果有 5 位来自 TX 的客户正在租一辆在 CA 注册的汽车,并且只有 2 位来自 NY 的客户在 CA 注册了租车,我将退还 5 个来自 TX 在 CA 租赁的汽车,依此类推,直到我完成所有注册状态。

第一个查询, 我得到的最接近的是这个查询:

SELECT registration_state, 
       Max(count) AS count 
FROM   (SELECT registration_state, 
               Count(a.state) AS count, 
               a.state 
        FROM   rental c 
               LEFT JOIN customer a 
                      ON a.customer_id = c.customer_id 
               LEFT JOIN vehicle b 
                      ON c.vehicle_id = b.vehicle_id 
        GROUP  BY registration_state, 
                  a.state)Z 
GROUP  BY registration_state 
ORDER  BY registration_state, 
          count DESC; 

+--------------------+-------+
| registration_state | count |
+--------------------+-------+
| AL                 |     1 |
| CA                 |     5 |
| DC                 |     1 |
| DE                 |     2 |
| FL                 |     3 |
| IL                 |     2 |
| IN                 |     1 |
| MD                 |     2 |
| MI                 |     1 |
| MN                 |     1 |
| MO                 |     1 |
| NE                 |     1 |
| NV                 |     2 |
| NY                 |     3 |
| OH                 |     2 |
| OR                 |     1 |
| PA                 |     1 |
| SC                 |     1 |
| TN                 |     3 |
| TX                 |     7 |
| WA                 |     1 |
+--------------------+-------+
21 rows in set (0.01 sec)

但是,它只显示在租车公司租车的那个州租用最多的客户状态的注册状态和计数,但没有显示客户状态,我希望显示客户状态。

第二个查询,以下查询为每个注册状态生成并返回每个客户状态的租金数量:

SELECT registration_state, 
       Count(d.state) AS count, 
       d.state 
FROM   rental f 
       LEFT JOIN customer d 
              ON d.customer_id = f.customer_id 
       LEFT JOIN vehicle e 
              ON f.vehicle_id = e.vehicle_id 
GROUP  BY registration_state, 
          d.state 
ORDER  BY registration_state, 
          count DESC; 

+--------------------+-------+-------+
| registration_state | count | state |
+--------------------+-------+-------+
| AL                 |     1 | NY    |
| CA                 |     5 | CA    |
| CA                 |     4 | MO    |
| CA                 |     2 | IN    |
| CA                 |     2 | TN    |
| CA                 |     2 | TX    |
| CA                 |     2 | OH    |
| CA                 |     1 | FL    |
| CA                 |     1 | AL    |
| CA                 |     1 | MI    |
| CA                 |     1 | NE    |
| CA                 |     1 | WA    |
| DC                 |     1 | CA    |
| DC                 |     1 | IL    |
| DC                 |     1 | TX    |
| DE                 |     2 | NY    |
| DE                 |     1 | FL    |
| FL                 |     3 | NY    |
| FL                 |     1 | AL    |
| FL                 |     1 | OH    |
| FL                 |     1 | CA    |
| FL                 |     1 | FL    |
| FL                 |     1 | MI    |
| FL                 |     1 | TX    |
| IL                 |     2 | OR    |
| IL                 |     1 | TX    |
| IL                 |     1 | CA    |
| IN                 |     1 | NV    |
| IN                 |     1 | CA    |
| MD                 |     2 | WA    |
| MD                 |     1 | OH    |
| MD                 |     1 | MD    |
| MI                 |     1 | PA    |
| MN                 |     1 | PA    |
| MN                 |     1 | TN    |
| MN                 |     1 | FL    |
| MO                 |     1 | NY    |
| MO                 |     1 | SC    |
| MO                 |     1 | OH    |
| MO                 |     1 | OR    |
| MO                 |     1 | CA    |
| MO                 |     1 | FL    |
| MO                 |     1 | TX    |
| NE                 |     1 | CA    |
| NV                 |     2 | FL    |
| NY                 |     3 | TX    |
| NY                 |     1 | CA    |
| NY                 |     1 | FL    |
| NY                 |     1 | MO    |
| NY                 |     1 | NY    |
| OH                 |     2 | OH    |
| OH                 |     1 | TN    |
| OH                 |     1 | NE    |
| OH                 |     1 | PA    |
| OH                 |     1 | DC    |
| OH                 |     1 | NY    |
| OR                 |     1 | IN    |
| OR                 |     1 | CA    |
| PA                 |     1 | MO    |
| PA                 |     1 | DC    |
| SC                 |     1 | FL    |
| SC                 |     1 | NY    |
| TN                 |     3 | TX    |
| TN                 |     2 | CA    |
| TN                 |     1 | FL    |
| TN                 |     1 | PA    |
| TN                 |     1 | MI    |
| TN                 |     1 | OH    |
| TN                 |     1 | OR    |
| TN                 |     1 | MO    |
| TX                 |     7 | NY    |
| TX                 |     4 | TX    |
| TX                 |     3 | FL    |
| TX                 |     2 | MO    |
| TX                 |     2 | MD    |
| TX                 |     2 | DC    |
| TX                 |     1 | IN    |
| TX                 |     1 | OH    |
| TX                 |     1 | CA    |
| TX                 |     1 | NV    |
| TX                 |     1 | OR    |
| TX                 |     1 | IL    |
| WA                 |     1 | TN    |
| WA                 |     1 | MI    |
+--------------------+-------+-------+
84 rows in set (0.00 sec)

如上表所示,如果将其与第一个表进行比较,您会发现第一个表仅返回该注册状态下租金最多的客户状态。

我想让它看起来像这样:

+--------------------+-------+-------+
| registration_state | count | state |
+--------------------+-------+-------+
| AL                 |     1 | NY    |
| CA                 |     5 | CA    |
| DC                 |     1 | CA    |
| DE                 |     2 | NY    |
| FL                 |     3 | NY    |
| IL                 |     2 | OR    |
| IN                 |     1 | NV    |
| MD                 |     2 | WA    |
| MI                 |     1 | PA    |
| MN                 |     1 | PA    |
| MO                 |     1 | NY    |
| NE                 |     1 | CA    |
| NV                 |     2 | FL    |
| NY                 |     3 | TX    |
| OH                 |     2 | OH    |
| OR                 |     1 | IN    |
| PA                 |     1 | MO    |
| SC                 |     1 | FL    |
| TN                 |     3 | TX    |
| TX                 |     7 | NY    |
| WA                 |     1 | TN    |
+--------------------+-------+-------+

我试过这样加入:

SELECT    registration_state, 
          MAX(count)
FROM      ( 
                    SELECT    registration_state, 
                              Count(d.state) AS count, 
                              d.state 
                    FROM      rental f 
                    LEFT JOIN customer d 
                    ON        d.customer_id = f.customer_id 
                    LEFT JOIN vehicle e 
                    ON        f.vehicle_id = e.vehicle_id 
                    GROUP BY  registration_state, 
                              d.state)W 
RIGHT JOIN 
          ( 
                    SELECT    registration_state AS registration_state2, 
                              count(a.state)     AS count2, 
                              a.state 
                    FROM      rental c 
                    LEFT JOIN customer a 
                    ON        a.customer_id = c.customer_id 
                    LEFT JOIN vehicle b 
                    ON        c.vehicle_id = b.vehicle_id 
                    GROUP BY  registration_state, 
                              a.state )z 
ON        z.count2=W.count 
AND      z.registration_state2=W.registration_state
GROUP BY registration_state
ORDER BY registration_state;


但它只返回与第一个查询相同的结果,如果我将任一子查询的状态添加到第一行的 select 语句中,并在最后按所述状态分组,我将得到第二个查询。

关于如何让它以我想要的方式返回有什么建议吗?

【问题讨论】:

【参考方案1】:

如果您运行的是 MySQL 8.0,则可以使用窗口函数为每个注册状态带来最多租金的客户状态:

select registration_state, state, cnt
from (
    select v.registration_state, c.state, count(*) as cnt,
        rank() over(partition by v.registration_state order by count(*) desc) rn
    from rental r
    inner join customer c on c.customer_id = r.customer_id 
    inner join vehicle  v on r.vehicle_id = v.vehicle_id 
    group  by v.registration_state, c.state 
) t
where rn = 1
order  by registration_state;

在早期版本中,它有点复杂。一种选择在having 子句中使用行限制相关子查询:

select v.registration_state, c.state, count(*) as cnt
from rental r
inner join customer c on c.customer_id = r.customer_id 
inner join vehicle  v on r.vehicle_id = v.vehicle_id 
group  by v.registration_state, c.state 
having count(*) = (
    select count(*)
    from rental r1
    inner join customer c1 on c1.customer_id = r1.customer_id 
    inner join vehicle  v1 on r1.vehicle_id = v1.vehicle_id 
    where c1.state = c.state and v1.registration_state = v.registration_state
    group by v1.registration_state, c1.state 
    order by count(*) desc limit 1
)

请注意,如果有的话,这两个查询都允许排名靠前。

【讨论】:

啊,我明白了,因此,该子查询中的窗口函数不是在最后进行分组,而是对每一行进行计数并为每一行返回一个结果,然后您获取排名第一的结果作为 rn。非常感谢!

以上是关于试图从 2 个正在加入的子查询中获取一列并且分组不起作用的主要内容,如果未能解决你的问题,请参考以下文章

通过 linq 对实体查询进行分组,以通过加入表来获取具有最新时间戳的一条记录

Oracle-视图,约束

oracle查询表中某一列所有不同分组的某个一列的最大值,并且返回这一行所有列的值。

加入和分组依据 - 选择列表中的列无效

在 ORACLE 中的子查询的列上求和

Laravel 查询 - 加入和分组