3 Where 子句没有条目给我 NULL

3 Where clauses one no entry gives me NULL

我有三个 tables,支出,收入,用户。我首先尝试获取用于获取有关用户的收入和支出信息的用户 ID。有了这个,我还与 DISTINCT 一起计算并减去它以获得当前收入。问题是如果 table 中的任何一个都没有输入示例支出 table 所以我得到 NULL 而不是数字。我该如何解决这个问题。我尝试了 IFNULL 但没有成功

我就是这样做的

SELECT SUM(DISTINCT user_earnings.amount) -  
       SUM(DISTINCT user_payouts.payout_amount) as total_earnings  
FROM user, user_earnings, user_payouts 
WHERE user.id = 103 
  and user_earnings.user_id = user.id 
  and user_payouts.user_id = user.id

编辑:我制作了当前的 tables user_earnings(问题仅在于 user_id 103

id  user_id  amount
1   102       250
2   102      1000
3   101      5000
4   102       352
18  102       375
19  102       442
20  103       338 <-----

user_payouts

id  user_id payout_amount   
1   102      500    
2   102      100    
3   101     1000

用户

id  payout_address
102 ***
103 ***

如您所见,付款没有关于 user_id 103 的条目,因为他从未进行过付款。这就是为什么我得到 null(我认为)

注1: 我绝对不会以这种方式使用 Distinct ...如果用户将来有另一个 earned_amount 用于 338,则第二个 338 不会添加到总数中。

注2: 请参阅我对 COALESCE 而不是 IFNULL 的用法。

注3: 我更新了您的连接语法。请确认我保留了您的加入。

编辑: 更新了答案和 fiddle 以解释每个用户的重复 earned_amount 以及每个用户的重复 payout_amounts

查看 Fiddle 以注意为用户 103 (400 + 400 - 100 - 100))

输入的两个重复项

点击Here for SQLFiddle

SELECT (
COALESCE(ue.earned_amount,0) - COALESCE(up.payout_amount,0)
) AS total_earnings
FROM user u 
JOIN (SELECT user_id, SUM(earned_amount) AS earned_amount 
       FROM Earned
       GROUP BY user_id) ue
    ON ue.user_id = u.id
JOIN (SELECT user_id, SUM(payout_amount) AS payout_amount
        FROM Payouts
        GROUP BY user_id) up 
    ON up.user_id = u.id

WHERE u.id = 103

性能说明:

如果您的 Earned 或 Payout tables 预计会很大,那么一些改进性能的想法将会是。

  1. 通过向每个嵌套查询添加一个 Where 子句来限制嵌套查询的 returned 结果集的大小,这样它们只有 return 结果 user_id 103 .

  2. 为 user_id 列的 Earned 和 Payout 添加索引。

  3. 或首先创建这些连接到带有索引的临时 table,然后将临时 table 连接到此查询

试试这个:

SELECT u.id, 
     (SUM(DISTINCT ue.amount) - 
       COALESCE(SUM(DISTINCT up.payout_amount),0)) as total_earnings
FROM 
  user u
  left outer join user_earnings ue on u.id = ue.user_id
  left outer join user_payouts up on u.id = up.user_id
WHERE 
  u.id = 103;

抱歉,我没有在上面付出足够的努力。虽然它适用于小样本,但上面的内容会分解为更大的样本,因为您要过滤掉单个用户获得两次相同金额的支出的任何实例。

我认为这是您真正的解决方案:

SELECT 
    u.id, 
    (ue.earnings - up.payouts) as total_earnings
FROM 
  user u
  inner join 
    (select distinct
        u1.id, 
        SUM(COALESCE(ue.amount,0)) as earnings 
     from 
        user u1 
        left join user_earnings ue on u1.id = ue.user_id group by u1.id) ue on u.id = ue.id
  inner join 
    (select distinct
        u1.id, 
        SUM(COALESCE(up.payout_amount,0)) as payouts 
     from 
        user u1 
        left join user_payouts up on u1.id = up.user_id group by u1.id) up on u.id = up.id
WHERE 
  u.id = 103;

只是为了好玩,这是另一个选项,更短:

SELECT 
    u.id, 
    ((select COALESCE(SUM(ue.amount),0) from user_earnings ue where ue.user_id = u.id) -
    (select COALESCE(SUM(up.payout_amount),0) from user_payouts up where up.user_id = u.id)) as total_earnings
FROM 
  user u
WHERE 
  u.id = 103;

您有 3 个问题 -- DISTINCTJOIN 后跟 GROUP BY,以及无法处理 NULL

SELECT  u.id,
        (
            SELECT ( IFNULL(SUM(amount), 0)
                FROM user_earnings WHERE user_id = u.id ) -
            SELECT ( IFNULL(SUM(payout_amount), 0 )
                FROM user_payouts  WHERE user_id = u.id )
        ) as total_earnings
    FROM  user u
    WHERE  u.id = 103;

应该都解决了。

  • DISTINCT 已经讨论过 - 给定用户可能有重复值。
  • JOIN 后跟 GROUP BY -- 我称之为 "inflate-deflate syndrone"。 JOIN 首先发生,从而增加了行数,然后 GROUP BY 试图对其进行补偿。通常这是一个性能问题;在你的情况下,它也会破坏数据。
  • 讨论了
  • NULL,但我认为这个公式是 'correct'。

这是 'rare' 的情况,子查询优于 LEFT JOIN。它避免了 SUM 的过度计算。 ghenghy 的第一个解决方案可能与 单个 u.id 一样好;我的应该适用于多个 ID。