Empty result of a query with 'group by' and 'having' clause

huangapple go评论103阅读模式
英文:

Empty result of a query with 'group by' and 'having' clause

问题

  1. select decimal_num, eri, max(check_date),
  2. concat(date_format(max(check_date), '%d.%m.%Y'), ' - ',
  3. date_format(date_add(max(check_date), interval 1 year), '%d.%m.%Y'))
  4. from osn
  5. join osn_check on osn_check.osn_id=osn.id
  6. group by osn.id;
英文:

I have two tables: osn

  1. +----+---------------------------------+--------+
  2. | id | decimal_num | eri | devices|
  3. +----+---------------------------------+--------+
  4. | 1 | AD2S80AUD | AD2S80AUD | 419 |
  5. | 2 | AD2S99 | AD2S99 | 419 |
  6. | 3 | F2K_14pin | 14pin | F2K |
  7. +----+---------------------------------+--------+

and osn_check:

  1. +----+--------+------------+------------+-------+------------+------+---------+
  2. | id | osn_id | check_date | check_type | works | conclusion | fio | comment |
  3. +----+--------+------------+------------+-------+------------+------+---------+
  4. | 2 | 1 | 2022-04-29 | 1 | | NULL | NULL | NULL |
  5. | 4 | 1 | 2023-05-24 | 0 | NULL | NULL | NULL | NULL |
  6. +----+--------+------------+------------+-------+------------+------+---------+

I need to select the fields from osn and osn_check where osn_check.check_date is maximal for each group. I execute this query:

  1. select decimal_num, eri, check_date,
  2. concat(date_format(check_date, '%d.%m.%Y'), ' - ',
  3. date_format(date_add(check_date, interval 1 year), '%d.%m.%Y'))
  4. from osn join osn_check on osn_check.osn_id=osn.id
  5. group by osn.id
  6. having check_date=max(check_date);

The result is empty. My desired result would be like this:

  1. AD2S80AUD | AD2S80AUD | 2023-05-24 | 24.05.2023 - 24.05.2024

How can I do this?

答案1

得分: 0

基本上,您想要进行过滤而不是聚合。根据您最初的尝试精神,我们可以使用相关子查询来返回每个项目的最新日期,因此:

  1. select o.*, oc.check_date, oc.check_type
  2. from osn o
  3. inner join osn_check oc on oc.osn_id = o.id
  4. where oc.check_date = (
  5. select max(oc1.check_date)
  6. from osn_check oc1
  7. where oc1.osn_id = o.id
  8. )

更现代的方法使用 row_number()(适用于 MySQL >= 8.0):

  1. select o.*, oc.check_date, oc.check_type
  2. from osn o
  3. inner join (
  4. select oc.*,
  5. row_number() over(partition by osn_id order by check_date desc) rn
  6. from osn_check oc
  7. ) oc on oc.osn_id = o.id
  8. where oc.rn = 1

如果在检查表中有许多行而在参考表中有很少行,也许使用侧向连接会更有效(需要 MySQL >= 8.0.14):

  1. select o.*, oc.check_date, oc.check_type
  2. from osn o
  3. cross join lateral (
  4. select oc.*
  5. from osn_check oc
  6. where oc.osn_id = o.id
  7. order by check_date desc limit 1
  8. ) oc

为了提高性能,请考虑在 osn_check(osn_id, check_date desc) 上创建一个索引,以便侧向子查询可以运行得更快。

英文:

Basically you want filtering rather than aggregation. In the spirit of your initial attempt, we could use a correlated subquery to return the latest date of each item, so:

  1. select o.*, oc.check_date, oc.check_type
  2. from osn o
  3. inner join osn_check oc on oc.osn_id = o.id
  4. where oc.check_date = (
  5. select max(oc1.check_date)
  6. from osn_check oc1
  7. where oc1.osn_id = o.id
  8. )

A more modern approach uses row_number() (MySQL >= 8.0):

  1. select o.*, oc.check_date, oc.check_type
  2. from osn o
  3. inner join (
  4. select oc.*,
  5. row_number() over(partition by osn_id order by check_date desc) rn
  6. from osn_check oc
  7. ) oc on oc.osn_id = o.id
  8. where oc.rn = 1

If there are many rows in the check table and few rows in the reference table, maybe a lateral join would be more efficient (requires MySQL >= 8.0.14):

  1. select o.*, oc.check_date, oc.check_type
  2. from osn o
  3. cross join lateral (
  4. select oc.*
  5. from osn_check oc
  6. where oc.osn_id = o.id
  7. order by check_date desc limit 1
  8. ) oc

For performance, consider an index on osn_check(osn_id, check_date desc), so the lateral subquery can run fast.

huangapple
  • 本文由 发表于 2023年5月25日 04:13:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76327098.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定