为什么加入表时ORDER BY结果会发生变化?

时间:2017-08-01 19:43:07

标签: mysql sql mariadb

有这两个表

-- table moves
+-----+-----------+--------+---------+
| id  | reference |  side  | balance |
+-----+-----------+--------+---------+
|  1  |     1     | credit |   1000  |
|  2  |     2     | credit |   500   |
+-----+-----------+--------+---------+

-- table join_table
+-----+
| id  |
+-----+
|  1  |
|  2  |
+-----+

现在我想从表#1中选择移动以及计算的净余额列

我用这个查询做到了

SELECT 
  moves.id,balance
  ,(@balance := @balance + (CASE side WHEN 'debit' THEN balance ELSE - balance END)) cum_balance
FROM 
   moves 
   CROSS JOIN (SELECT @balance := 0 blc)t
ORDER BY
     moves.id ASC
 ;

这就是我想要的结果

-- result #1
+-----+----------+---------------+
| id  | balance  |  cum_balance  |
+-----+----------+---------------+
|  1  |   1000   |    -1000      |
|  2  |   500    |    -1500      |
+-----+----------+---------------+

当我想计算净余额时,但当我订购表格DESC时,我只需更换订单

ORDER BY moves.id DESC

我得到了预期的结果

-- result #2
+-----+----------+---------------+
| id  | balance  |  cum_balance  |
+-----+----------+---------------+
|  2  |   500    |    -500       |
|  1  |   1000   |    -1500      |
+-----+----------+---------------+

到目前为止,当我将表连接到其他表时,问题就开始了,比如

SELECT 
  moves.id,balance
  ,(@balance := @balance + (CASE side WHEN 'debit' THEN balance ELSE - balance END)) cum_balance

FROM 
   moves 
   INNER JOIN join_table ON join_table.id = moves.reference -- remove this join to work
   CROSS JOIN (SELECT @balance := 0 blc)t
ORDER BY
     moves.id DESC
 ;

我得错了结果!!

-- result #3
+-----+----------+---------------+
| id  | balance  |  cum_balance  |
+-----+----------+---------------+
|  2  |   500    |    -1500      |
|  1  |   1000   |    -1000      |
+-----+----------+---------------+

我期望得到与结果#2相同的结果,我不知道这里发生了什么。我希望我能理解为什么当我加入桌子时结果会发生变化?!。和如何在加入表格时获得结果#2的预期结果?

这是一个SQLfiddle(http://sqlfiddle.com/#!9/5ea79/3),在问题中提到了相同的模式。

1 个答案:

答案 0 :(得分:2)

我不确定原因,但如果您在查询中显示@balance,您会看到变量不匹配。那是因为计算过程的顺序错误。此外,如果ORDER BY id ASC正常工作。

要解决此问题,请执行连接,然后执行变量计算。

<强> SQL DEMO

SELECT *,
      (@balance := @balance + (CASE side 
                               WHEN 'debit' 
                               THEN balance ELSE - balance END)) cum_balance
FROM (
      SELECT 
        moves.id, 
        balance,
        side  
       FROM 
         moves 
         INNER JOIN join_table ON join_table.id = moves.reference
      ORDER BY
           moves.id DESC
      ) Q
CROSS JOIN (SELECT @balance := 0 blc)t
 ;