GROUP BY按列聚合

时间:2016-08-07 02:25:41

标签: mysql sql h2

我遇到了一个问题,每当我尝试使用GROUP BY时,H2都会告诉我需要在GROUP BY子句中添加某些列名,因为根据我的研究,它是不清楚H2如何使用非重复数据对列进行排序。

这是一个详细说明的例子:

人员表

+------------+------------+
| ID         | Name       |
+============+============+
| 1          | John       |
+------------+------------+
| 2          | Jane       |
+------------+------------+

宠物表

+------------+------------+------------+------------+
| ID         | PERSON_ID  |    NAME    | BIRTHDATE  |
+============+============+============+============+
| 1          |      1     |  Rufus     |  2012      |
+------------+------------+------------+------------+
| 2          |      1     |  Ben       |  2014      | 
+------------+------------+------------+------------+

假设我想要属于约翰的所有最老的宠物。

SELECT PERSON.NAME, PET.NAME, PET.BIRTHDATE FROM PERSON
INNER JOIN PET ON PET.PERSON_ID = PERSON.ID
GROUP BY PERSON.NAME
ORDER BY PET.BIRTHDATE ASC

这在MySQL中完全有效,因为它只是按PERSON.NAME分组,默认情况下,选择集合中的第一条记录。但是,在H2中,它需要具有MAXMIN等聚合

正如您在本示例中所看到的,问题在于您可以使用MIN来正确排序BIRTHDATE,但似乎没有任何可用于排序的聚合函数{{1基于最早的NAME

2 个答案:

答案 0 :(得分:0)

在这种情况下,你可以随时诉诸NOT EXISTS,如果这个人没有生育日期较小的宠物,那么宠物就是最老的(如果两只宠物的年龄相同,两者都是最老的宠物)那个人,然后都被选中了):

SELECT p.NAME, q.NAME, q.BIRTHDATE
FROM PERSON p
  INNER JOIN PET q ON q.PERSON_ID = p.ID AND NOT EXISTS (
    SELECT * FROM PET WHERE PERSON_ID = p.ID AND BIRTHDATE < q.BIRTHDATE
  )
ORDER BY q.BIRTHDATE ASC

如果你坚持GROUP BY,你可以这样做:

SELECT a.name, b.name, b.BIRTHDATE FROM (
  SELECT p.id, MIN(q.BIRTHDATE) birthdate FROM PERSON p
  INNER JOIN PET q ON q.PERSON_ID = p.ID
  GROUP BY p.ID
) o INNER JOIN PERSON a ON a.ID = o.ID
  INNER JOIN PET b ON b.PERSON_ID = a.ID AND b.BIRTHDATE = o.BIRTHDATE
ORDER BY b.BIRTHDATE

如果您可以使用WITH,则可以更轻松地编写查询。

答案 1 :(得分:0)

如果你想要最老的宠物,我建议:

SELECT p.NAME, pt.NAME, pt.BIRTHDATE
FROM PERSON p INNER JOIN
     PET pt
     ON pt.PERSON_ID = p.ID
WHERE pt.BIRTHDATE = (SELECT MIN(pt2.BIRTHDATE)
                      FROM pet pt2
                      WHERE  pt2.PERSON_ID = PT.PERSON_ID
                     );

这明确选择了最早出生年份的宠物(每个人)。不需要聚合。

您也可以仅在JOIN

中使用FROM对此进行说明
SELECT p.NAME, pt.NAME, pt.BIRTHDATE
FROM PERSON p INNER JOIN
     PET pt
     ON pt.PERSON_ID = p.ID JOIN
     (SELECT PERSON_ID, MIN(pt2.BIRTHDATE) as MINBT
      FROM pet pt2
      GROUP BY pt2.PERSON_ID
     ) pt2
     ON  pt2.PERSON_ID = PT.PERSON_ID;