为什么 sql 给出的结果和不正确?
Why sql give not right sum in result?
tableBalance
中的行数:
行 Amount
的类型为十进制 10,1
我们是 select:
SELECT
u.UserID as UserID,
(ifnull(b.BalanceDebit,0) - ifnull(bc.BalanceCredit, 0)) as Balance,
ifnull(bc.BalanceCredit, 0) as BalanceCredit
FROM
Users as u
LEFT JOIN
(
SELECT
UserID,
SUM(Amount) as BalanceDebit
FROM
Balance
WHERE
Operation='debit' AND StatusPay = 'success'
GROUP BY
UserID
) as b ON u.UserID = u.UserID
LEFT JOIN
(
SELECT
UserID,
SUM(Amount) as BalanceCredit
FROM
Balance
WHERE
Operation='credit' AND StatusPay = 'success'
GROUP BY
UserID
) as bc ON bc.UserID = u.UserID
WHERE
u.UserID != '12'
在 select 之后,结果我们看到下一行:
但是结果平衡不对。结果显示所有用户的余额都是 10.0,但只有一个用户 (UsersID = 40) 有 10.0.
请告诉我 sql quesry 哪里出错了? select总和怎么对?
您的问题是您的第一个 LEFT OUTER JOIN:
ON u.UserID = u.UserID
应该是
ON u.UserID = b.UserID
另外,如果你想找到平衡点,我想你会把所有的贷方都拿走,然后减去所有的借方。所以不是这个:
ifnull(b.BalanceDebit,0) - ifnull(bc.BalanceCredit, 0)
不应该是这个吗?
ifnull(b.BalanceCredit,0) - ifnull(bc.BalanceDebit, 0)
可以使用 CASE 将两个左连接合并为一个(并修复错误的连接条件):
SELECT
u.UserID AS UserID,
(ifnull(b.BalanceDebit,0) - ifnull(b.BalanceCredit, 0)) AS Balance,
ifnull(b.BalanceCredit, 0) AS BalanceCredit
FROM
Users AS u
LEFT JOIN
(
SELECT
UserID,
SUM(CASE WHEN Operation='debit' AND StatusPay = 'success' THEN Amount end) AS BalanceDebit,
SUM(CASE WHEN Operation='credit' AND StatusPay = 'success' THEN Amount end) AS BalanceCredit
FROM
Balance
WHERE
(Operation='debit' AND StatusPay = 'success')
OR
(Operation='credit' AND StatusPay = 'success')
GROUP BY
UserID
) AS b ON b.UserID = u.UserID
Bill Gregg 指出的 JOIN 条件是导致结果不正确的主要原因。可以重写查询以避免必须加入 Balance 两次:
SELECT u.UserID
, COALESCE(b.CalculatedBalance, 0)
, COALESCE(b.BalanceCredit, 0)
FROM Users AS u
LEFT JOIN
(SELECT UserID,
SUM(CASE Operation
WHEN 'debit' THEN Amount*-1
WHEN 'credit' THEN Amount
END) AS CalculatedBalance,
SUM(CASE Operation
WHEN 'credit' THEN Amount
END) AS BalanceCredit
FROM Balance
WHERE StatusPay = 'success'
GROUP BY UserID
) AS b
ON u.UserID = b.UserID
WHERE u.UserID != '12'
不需要子查询,同样的结果可以这样实现:
SELECT
u.UserID,
SUM(CASE WHEN b.operation = 'debit' THEN b.operation ELSE 0 END) balance_debit,
SUM(CASE WHEN b.operation = 'credit' THEN b.operation ELSE 0 END) balance_credit,
SUM(CASE WHEN b.operation = 'debit' THEN b.operation ELSE 0 END) -
SUM(CASE WHEN b.operation = 'credit' THEN b.operation ELSE 0 END) balance
FROM users u
LEFT JOIN
balance b
ON u.UserID = b.UserID AND b.StatusPay = 'success'
WHERE u.UserID <> 12
GROUP BY u.USERID
tableBalance
中的行数:
行 Amount
的类型为十进制 10,1
我们是 select:
SELECT
u.UserID as UserID,
(ifnull(b.BalanceDebit,0) - ifnull(bc.BalanceCredit, 0)) as Balance,
ifnull(bc.BalanceCredit, 0) as BalanceCredit
FROM
Users as u
LEFT JOIN
(
SELECT
UserID,
SUM(Amount) as BalanceDebit
FROM
Balance
WHERE
Operation='debit' AND StatusPay = 'success'
GROUP BY
UserID
) as b ON u.UserID = u.UserID
LEFT JOIN
(
SELECT
UserID,
SUM(Amount) as BalanceCredit
FROM
Balance
WHERE
Operation='credit' AND StatusPay = 'success'
GROUP BY
UserID
) as bc ON bc.UserID = u.UserID
WHERE
u.UserID != '12'
在 select 之后,结果我们看到下一行:
但是结果平衡不对。结果显示所有用户的余额都是 10.0,但只有一个用户 (UsersID = 40) 有 10.0.
请告诉我 sql quesry 哪里出错了? select总和怎么对?
您的问题是您的第一个 LEFT OUTER JOIN:
ON u.UserID = u.UserID
应该是
ON u.UserID = b.UserID
另外,如果你想找到平衡点,我想你会把所有的贷方都拿走,然后减去所有的借方。所以不是这个:
ifnull(b.BalanceDebit,0) - ifnull(bc.BalanceCredit, 0)
不应该是这个吗?
ifnull(b.BalanceCredit,0) - ifnull(bc.BalanceDebit, 0)
可以使用 CASE 将两个左连接合并为一个(并修复错误的连接条件):
SELECT
u.UserID AS UserID,
(ifnull(b.BalanceDebit,0) - ifnull(b.BalanceCredit, 0)) AS Balance,
ifnull(b.BalanceCredit, 0) AS BalanceCredit
FROM
Users AS u
LEFT JOIN
(
SELECT
UserID,
SUM(CASE WHEN Operation='debit' AND StatusPay = 'success' THEN Amount end) AS BalanceDebit,
SUM(CASE WHEN Operation='credit' AND StatusPay = 'success' THEN Amount end) AS BalanceCredit
FROM
Balance
WHERE
(Operation='debit' AND StatusPay = 'success')
OR
(Operation='credit' AND StatusPay = 'success')
GROUP BY
UserID
) AS b ON b.UserID = u.UserID
Bill Gregg 指出的 JOIN 条件是导致结果不正确的主要原因。可以重写查询以避免必须加入 Balance 两次:
SELECT u.UserID
, COALESCE(b.CalculatedBalance, 0)
, COALESCE(b.BalanceCredit, 0)
FROM Users AS u
LEFT JOIN
(SELECT UserID,
SUM(CASE Operation
WHEN 'debit' THEN Amount*-1
WHEN 'credit' THEN Amount
END) AS CalculatedBalance,
SUM(CASE Operation
WHEN 'credit' THEN Amount
END) AS BalanceCredit
FROM Balance
WHERE StatusPay = 'success'
GROUP BY UserID
) AS b
ON u.UserID = b.UserID
WHERE u.UserID != '12'
不需要子查询,同样的结果可以这样实现:
SELECT
u.UserID,
SUM(CASE WHEN b.operation = 'debit' THEN b.operation ELSE 0 END) balance_debit,
SUM(CASE WHEN b.operation = 'credit' THEN b.operation ELSE 0 END) balance_credit,
SUM(CASE WHEN b.operation = 'debit' THEN b.operation ELSE 0 END) -
SUM(CASE WHEN b.operation = 'credit' THEN b.operation ELSE 0 END) balance
FROM users u
LEFT JOIN
balance b
ON u.UserID = b.UserID AND b.StatusPay = 'success'
WHERE u.UserID <> 12
GROUP BY u.USERID