【问题标题】:MYSQL query to display max values of column grouped by inner join columnMYSQL查询以显示按内部连接列分组的列的最大值
【发布时间】:2021-07-22 03:22:28
【问题描述】:

我有两张桌子

飞行员

pilot_id first_name last_name status hub
1 fname1 lname1 1 YBBN
2 fname2 lname2 0 YSSY
3 fname3 lname3 1 YMML
4 fname4 lname4 1 YBBN
5 fname5 lname5 1 EGLL
6 fname6 lname6 1 EGLL
7 fname7 lname7 1 EGLL
8 fname8 lname8 1 YPAD

PIREPS

pirep_id pilot_id date landing_rate accepted
1 1 2021-04-01 -113 1
2 1 2021-04-02 -110 1
3 1 2021-04-03 -200 1
4 2 2021-04-04 -20 1
5 2 2021-04-05 -120 1
6 3 2021-04-06 -130 1
7 3 2021-04-07 -132 1
8 4 2021-04-08 -91 1
9 5 2021-04-09 -64 1
10 6 2021-04-10 -47 0
11 6 2021-04-11 -112 1
12 7 2021-04-12 -113 1
13 7 2021-04-13 -201 1
14 1 2021-04-14 -300 0
15 1 2021-04-15 -301 1

预期结果

pilot_id first_name last_name hub landing_rate date pirep_id
2 fname2 lname2 YSSY -20 2021-04-04 4
5 fname5 lname5 EGLL -64 2021-04-09 9
4 fname4 lname4 YBBN -91 2021-04-08 8
3 fname3 lname3 YMML -130 2021-04-06 6
8 fname8 lname8 YPAD -301 2021-04-15 15

如果我只按飞行员 ID 分组并显示相关飞行员的最佳着陆率和他们完成飞行的日期,下面的代码会给我预期的输出

SELECT pi.first_name,pi.last_name,p.pirep_id,p.pilot_id,p.date,p.landing_rate
FROM qvi_pireps p
LEFT JOIN qvi_pilots pi on p.pilot_id=pi.pilot_id
INNER JOIN
    (SELECT pilot_id as pil,date as da,MAX(landing_rate) AS max_landing_rate
    FROM qvi_pireps
    where landing_rate<0 GROUP BY pilot_id) grouppedp 
ON p.pilot_id = grouppedp.pil 
AND p.landing_rate = grouppedp.max_landing_rate  
where pi.status=1 and
accepted=1
group by p.pilot_id ORDER BY `grouppedp`.`max_landing_rate`  DESC,p.date asc limit 20

以上查询输出

first_name last_name pirep_id pilot_id date landing_rate
fname2 lname2 4 2 2021-04-04 -20
fname5 lname5 9 5 2021-04-09 -64
fname4 lname4 8 4 2021-04-08 -91
fname1 lname1 2 1 2021-04-02 -110
fname6 lname6 11 6 2021-04-11 -112
fname7 lname7 12 7 2021-04-12 -113
fname3 lname3 6 3 2021-04-06 -130
fname8 lname8 15 8 2021-04-15 -301

当我将 group by p.pilot_id 更改为 group by pi.hub 时,我收到了独特的集线器,但是飞行员、着陆率和日期与应该是最好的不匹配

基本上,我想要实现的是获取每个飞行员的 MAX(landing_rate),其中 Pilot.status=1 & flight.accepted=1,然后按 Pilot.hub 分组以显示具有最高着陆率的最佳枢纽飞行员和他们达到着陆率的日期

任何帮助将不胜感激!

【问题讨论】:

  • 您的查询缺少 select 部分。还请提供一些示例数据(不是图像),并从示例数据中得到预期的结果。下面是一个很好的例子来说明 SQL 问题应该是怎样的:meta.stackoverflow.com/a/271056/460557
  • 感谢您的提示!我已经采取了这些措施:)

标签: mysql join group-by


【解决方案1】:

这个:

SELECT pilot_id, date, MAX(landing_rate)
FROM qvi_pireps
GROUP BY pilot_id

是无效的 SQL。您按飞行员分组并选择一个日期。哪个日期?该表中每个飞行员有很多日期。您必须在 date 上应用一些聚合函数才能使其有效。 MySQL 应该在这里引发一个异常(我相信它会,你是否从作弊模式更改为SET sql_mode = 'ONLY_FULL_GROUP_BY';。这应该默认设置,因为这似乎不是这种情况,我猜你正在使用旧版本的 MySQL。

除了这个和不适当的外部联接以及在您的子查询中缺少accepted 签入(这可能是您看到不正确日期的主要原因)之外,您的查询看起来相当不错。只有在您的主要查询中,您才能按飞行员再次分组,这根本没有意义。也许您在某些时候重写查询时错误地留下了它。这是您更正的查询:

SELECT pil.first_name, pil.last_name, pir.pirep_id, pil.pilot_id, pir.date, pir.landing_rate
FROM qvi_pilots pil
JOIN qvi_pireps pir ON pir.pilot_id = pil.pilot_id AND pir.accepted = 1
JOIN
(
  SELECT pilot_id, MAX(landing_rate) AS max_landing_rate
  FROM qvi_pireps
  WHERE accepted = 1
  GROUP BY pilot_id
) grouppedp ON grouppedp.pilot_id = pir.pilot_id AND grouppedp.max_landing_rate = pir.landing_rate
WHERE pil.status = 1
ORDER BY pir.landing_rate DESC, pir.date ASC
LIMIT 20;

为了可读性,虽然我更喜欢 IN 子句而不是连接:

SELECT pil.first_name, pil.last_name, pir.pirep_id, pil.pilot_id, pir.date, pir.landing_rate
FROM qvi_pilots pil
JOIN qvi_pireps pir ON pir.pilot_id = pil.pilot_id
                    AND pir.accepted = 1
                    AND (pir.pilot_id, pir.landing_rate) IN
                    (
                      SELECT pilot_id, MAX(landing_rate)
                      FROM qvi_pireps
                      WHERE accepted = 1
                      GROUP BY pilot_id
                    )
WHERE pil.status = 1
ORDER BY pir.landing_rate DESC, pir.date ASC
LIMIT 20;

(顺便说一句,NOT EXISTS (&lt;a greater landing rate for the pilot&gt;) 也可以实现。)

在当前的 MySQL 版本中,我们宁愿使用窗口函数来访问 qvi_pireps 表一次:

SELECT first_name, last_name, pirep_id, pilot_id, date, landing_rate
FROM
(
  SELECT
    pil.first_name, pil.last_name, pir.pirep_id, pil.pilot_id, pir.date, pir.landing_rate,
    MAX(pir.landing_rate) OVER (PARTITION BY pil.pilot_id) AS max_landing_rate
  FROM qvi_pilots pil
  JOIN qvi_pireps pir ON pir.pilot_id = pil.pilot_id AND pir.accepted = 1
  WHERE pil.status = 1
) with_max_landing_rate
WHERE landing_rate = max_landing_rate
ORDER BY landing_rate DESC, date ASC
LIMIT 20;

更新:对旧 MySQL 版本的查询相同,但针对每个中心的最佳费率而不是每个试点的最佳费率。

毕竟,这仅仅意味着我们必须为每个集线器而不是每个飞行员寻找MAX(landing_rate)

SELECT pil.first_name, pil.last_name, pir.pirep_id, pil.pilot_id, pir.date, pir.landing_rate
FROM qvi_pilots pil
JOIN qvi_pireps pir ON pir.pilot_id = pil.pilot_id
                    AND pir.accepted = 1
                    AND (pil.hub, pir.landing_rate) IN
                    (
                      SELECT pl.hub, MAX(pr.landing_rate)
                      FROM qvi_pireps pr
                      JOIN qvi_pilots pl USING (pilot_id) 
                      WHERE pr.accepted = 1 AND pl.status = 1
                      GROUP BY pl.hub
                    )
WHERE pil.status = 1
ORDER BY pir.landing_rate DESC, pir.date ASC
LIMIT 20;

【讨论】:

  • 非常感谢您的帮助,我已将查询更改为按照建议使用 IN 语句。我得到了飞行员表,这不是我想要的,所以一开始就将 from 语句翻转为 pireps。现在我得到了状态为 1 的飞行员的预期输出,我需要按其 HUB 对所有飞行员进行分组,并为每个具有匹配的相应 pirep 的中心获得最佳飞行员(由着陆率确定)
  • FROM 子句中的表顺序应该对查询没有影响。至于集线器:相同,相同。您无需为每个飞行员寻找max(landing_rate),而是为每个集线器寻找它。为此,您必须在子查询中加入状态一飞行员。在 MySQL 8 查询中更容易,您只需将分区子句从 Pilot 更改为 hub。
  • ... 除非您希望飞行员具有最大速率并从该结果中获得每个集线器的最大行数。这需要将查询放在子查询中并在此基础上进行构建。您的描述听起来像是您想要的,但很可能您只想要每个集线器的最佳行,这更容易。
  • 更正每个集线器的最佳行(i.stack.imgur.com/bvwjR.png 用于上下文)
  • 好吧,如前所述,在您的子查询中加入状态一飞行员,按集线器而不是飞行员分组,仅此而已。祝你好运。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-30
  • 2020-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多