3 where子句一个没有条目给我NULL

时间:2017-05-03 19:16:40

标签: mysql null mariadb

我有三张桌子,付款,收入,用户。我尝试首先获得用于获取有关用户的收入和付款信息的用户ID。有了这个,我还与DISTINCT一起计算并减去它以获得CURRENT收益。问题是如果任何表没有输入示例支付表,所以我得到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
编辑:我制作了当前的表格 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(我认为)

3 个答案:

答案 0 :(得分:1)

<强>注1: 我肯定不会以这种方式使用Distinct ...如果将来的用户有338的另一个earn_amount,那么第二个338将不会被添加到总数中。

<强>注2: 请参阅我对COALESCE的使用而不是IFNULL。

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

编辑:更新了答案,并为每个用户重复的earn_amounts帐户以及每位用户的重复payout_amounts提供了支持

查看小提琴,注意为用户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

效果说明:

如果您的获奖或奖金表预计会很大,那么性能改进的一些想法就会出现。

  1. 通过向每个查询添加Where子句来限制嵌套查询的返回结果集的大小,以便它们只返回user_id 103的结果。

  2. 为列user_id添加索引到已获奖和付款。

  3. 或者首先使用索引创建这些连接到临时表,然后将临时表连接到此查询

答案 1 :(得分:1)

试试这个:

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;

答案 2 :(得分:0)

您有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 - 我称之为&#34; inflate-deflate syndrone&#34;。 JOIN首先发生,从而使行数膨胀,然后GROUP BY尝试补偿它。通常这是一个性能问题;在你的情况下,它也会破坏数据。
  • 讨论了
  • NULL,但我认为这个提法是正确的。

这是一个罕见的&#39;子查询优于LEFT JOIN的情况。它避免了SUM的过度计算。 ghenghy的第一个解决方案可能与 u.id一样好;我应该为多个ID工作。