Same Query returns different results (MySQL Group By)

风流意气都作罢 提交于 2020-01-07 02:50:28

问题


This only happens for queries that force GROUP BY after ORDER BY.

Goal:

Get latest balance for each unit for the given cardID.

Table:

cardID  |  unit     |  balance  |  date
--------|-----------|-----------|--------------
A1      |  DEPOSIT  |  100      |  2016-05-01
A1      |  DEPOSIT  |  90       |  2016-05-02
A1      |  DEPOSIT  |  80       |  2016-05-03
A1      |  DEPOSIT  |  75       |  2016-05-04
A1      |  MINUTE   |  1000     |  2016-05-01
A1      |  MINUTE   |  900      |  2016-05-02
A1      |  MINUTE   |  800      |  2016-05-03

Query:

SELECT * FROM (
    SELECT unit, balance
    FROM cardBalances
    WHERE cardID = 'A1'
    ORDER BY date DESC
) AS cb
GROUP BY cb.unit;

Expected Result (MySQL v5.5.38):

unit     |  balance  
---------|-----------
DEPOSIT  |  75       
MINUTE   |  800      

Unexpected Result (MySQL v5.7.13):

unit     |  balance
---------|-----------
DEPOSIT  |  100
MINUTE   |  1000

After upgrading to MySQL v5.7.13, the result returns the initial balances; as if no deduction occurred for the given card.

Is this a bug in MySQL version?
Would you suggest any other, more reliable way to solve this?


回答1:


This is a bug in your use of the database. MySQL is quite explicit that when you include columns in the SELECT clause in an aggregation query -- and they are not in the GROUP BY -- then they come from indeterminate rows.

Such syntax is specific to MySQL. It is not only a bad idea to learn, but it simply normally not work in other databases.

You can do what you want in various ways. Here is one:

SELECT cb.*
FROM cardBalances cb
WHERE cardId = 'A1' AND
      cb.date = (SELECT MAX(date)
                 FROM cardBalances cb2
                 WHERE cb2.cardId = 'A1' AND cb2.unit = cb.unit
                );

This has the advantage that it can use an index on cardBalances(unit, CardId, date).




回答2:


Just an other perspective by adding a row number based on the cardId, unit and descending order of date.

Query

select t1.unit, t1.balance from 
(
    select cardId, unit, balance, `date`, 
    (
        case unit when @curA
        then @curRow := @curRow + 1 
        else @curRow := 1 and @curA := unit end 
    ) + 1 as num 
    from cardBalances t, 
    (select @curRow := 0, @curA := '') r 
    order by cardId, unit, `date` desc 
)t1 
where t1.num = 1
order by t1.unit;

SQL Fiddle Demo



来源:https://stackoverflow.com/questions/38719922/same-query-returns-different-results-mysql-group-by

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!