MySQL groupwise MAX()返回意外结果

时间:2013-03-25 10:55:31

标签: mysql sql group-by greatest-n-per-group

表:贷款

Loan_no     Amount        SSS_no              Loan_date

7           700.00        0104849222          2010-01-03 
8           200.00        0104849222          2010-02-28
9           300.00        0119611199          2010-11-18
10          150.00        3317131410          2012-11-28
11          600.00        0104849222          2011-01-03
14          175.00        3317131410          2012-12-05
15          260.00        3317131410          2013-02-08
16          230.00        0104849222          2013-03-06
17          265.00        0119611199          2011-04-30
18          455.00        3317131410          2013-03-10

期望的结果:

我想要检索最新的贷款 由每个人(由他们的SSS号码确定)。该 结果应如下:

Loan_no           Amount                SSS_no                Loan_date

16                230.00              0104849222              2013-03-06
17                265.00              0119611199              2011-04-30
18                455.00              3317131410              2013-03-10

QUERY#1已使用:

SELECT * FROM loan GROUP BY SSS_no ORDER BY Loan_date DESC

MYSQL结果

Loan_no             Amount              SSS_no                  Loan_date

10                  150.00            3317131410                2012-11-28
9                   300.00            0119611199                2010-11-18
7                   700.00            0104849222                2010-01-03

QUERY#2已使用:

SELECT Loan_no, Amount, SSS_no, max(Loan_date) FROM loan GROUP BY SSS_no

MYSQL结果

Loan_no            Amount                SSS_no                Loan_date

7                  700.00                0104849222            2013-03-06
9                  300.00                0119611199            2011-04-30
10                 150.00                3317131410            2013-03-10

有人能解决我的问题吗?感谢。

3 个答案:

答案 0 :(得分:1)

请改为尝试:

SELECT l1.*
FROM loan AS l1
INNER JOIN
(
   SELECT SSS_no, MAX(Loan_date) LatestDate
   FROM loan
   GROUP BY SSS_no
) AS l2  ON l1.SSS_no    = l2.SSS_no 
        AND l1.loan_date = l2.LatestDate;

SQL Fiddle Demo

这会给你:

| LOAN_NO | AMOUNT |     SSS_NO |  LOAN_DATE |
----------------------------------------------
|      16 |    230 |  104849222 | 2013-03-06 |
|      17 |    265 |  119611199 | 2011-04-30 |
|      18 |    455 | 3317131410 | 2013-03-10 |

答案 1 :(得分:1)

MySQL reference提出了几种解决方法。最简单的是子查询:

SELECT *
FROM   loan l1
WHERE  loan_date=(SELECT MAX(l2.loan_date)
              FROM loan l2
              WHERE l1.sss_no = l2.sss_no);

鉴于this type of subqueries potentially have bad performance,他们还建议使用JOIN(基本上是Mahmoud Gamal的答案):

SELECT l1.loan_no, l1.amount, l1.sss_no, l1.loan_date
FROM loan l1
JOIN (
  SELECT loan_no, MAX(loan_date) AS loan_date
  FROM loan
  GROUP BY sss_no) AS l2
  ON l1.loan_date = l2.loan_date AND l1.sss_no = l2.sss_no;

第三种选择是:

SELECT l1.loan_no, l1.amount, l1.sss_no, l1.loan_date
FROM loan l1
LEFT JOIN loan l2 ON l1.sss_no = l2.sss_no AND l1.loan_date < l2.loan_date
WHERE l2.sss_no IS NULL;

LEFT JOIN的工作原理是,当l1.loan_date处于最大值时,后来有l2.loan_date,因此l2行的值将为NULL。

所有这些都应具有相同的输出,但性能可能不同。

答案 2 :(得分:1)

您获得意外结果的原因是因为您只在GROUP BY列表中的一列上使用SELECT,并且您没有在所有列上使用任何聚合函数。

MySQL使用GROUP BY函数的扩展名,当您没有GROUP BY或聚合SELECT列表中的所有项目时,可能会导致意外结果。 (见MySQL Extensions to GROUP BY

来自MySQL文档:

  

MySQL扩展了GROUP BY的使用,因此选择列表可以引用GROUP BY子句中未命名的非聚合列。 ...您可以通过避免不必要的列排序和分组来使用此功能来获得更好的性能。但是,当GROUP BY中未命名的每个非聚合列中的所有值对于每个组都相同时,这非常有用。服务器可以自由选择每个组中的任何值,因此除非它们相同,否则所选的值是不确定的。此外,添加ORDER BY子句不会影响每个组中值的选择。选择值后会对结果集进行排序,而ORDER BY不会影响服务器选择的值。

确保返回正确结果的唯一方法是将查询更改为正确聚合和GROUP BY

所以你可以使用类似的东西:

select l1.loan_no,
  l1.amount,
  l1.SSS_no,
  l1.loan_date
from loan l1
inner join
(
  select SSS_no, max(loan_date) Loan_date
  from loan
  group by SSS_no
) l2
  on l1.SSS_no = l2.SSS_no
  and l1.loan_date = l2.loan_date

请参阅SQL Fiddle with Demo

这实现了一个子查询,以获取每个max(loan_date)的{​​{1}}。然后,在SSS_no和最大SSS_no上将此子查询连接回您的表格,这样可以保证您获得每个loan_date的正确结果。