如果未找到任何记录,则返回0作为SUM结果

时间:2018-12-28 10:25:15

标签: mysql join

我正在尝试总结特定用户在过去7天(实际天是第7天)每天的活动卡路里。有表用户和活动表,以及映射表user_activities。

以下示例适用于id = 1;

的用户
  

过去7天(今天第7天)每天的卡路里汇总* /

SELECT  
    DATE(a.end_time), SUM(a.calories)
FROM
    activities a
JOIN
    user_activities uc ON uc.activity_id = a.id
WHERE
    uc.user_id = 1
    AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 6 DAY
GROUP BY 
    DATE(a.end_time) DESC

该查询返回以下结果集:

2018-12-28   9600
2018-12-27   1200
2018-12-26   1200
2018-12-25   1200
2018-12-24   4800
2018-12-22   1200

这是正确的,但是现在我的问题是,正如您在列表中看到的那样,未列出12-23-2018,因为该日期没有活动。现在我要显示

2018-12-23   0

一无所有。

如何获得所需的结果?

感谢您的帮助

我也尝试了IFNULL和COALESCE,但到目前为止还没有运气

  

过去7天(今天第7天)每天的卡路里汇总* /

SELECT  
    DATE(a.end_time), SUM(a.calories)
FROM
    activities a
JOIN 
    user_activities uc ON uc.activity_id = a.id
WHERE 
    uc.user_id = 1
    AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 6 DAY
GROUP BY
    DATE(a.end_time) DESC

结果:

2018-12-28   9600
2018-12-27   1200
2018-12-26   1200
2018-12-25   1200
2018-12-24   4800
2018-12-22   1200

预期结果:

2018-12-28   9600
2018-12-27   1200
2018-12-26   1200
2018-12-25   1200
2018-12-24   4800
2018-12-23      0
2018-12-22   1200

Activities表:

enter image description here

4 个答案:

答案 0 :(得分:0)

您可以尝试以下操作-使用左联接

SELECT  DATE(a.end_time), SUM(a.calories)
FROM activities a
left JOIN user_activities uc ON uc.activity_id = a.id
Where uc.user_id = 1 AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 6 DAY
GROUP BY DATE(a.end_time) order by DATE(a.end_time) DESC

答案 1 :(得分:0)

如果您的活动表很可能在特定的一天没有列出活动,则fa06的技巧将无法解决。解决这种情况的一种简单方法是在进行总和之前添加一些零记录:

SELECT DATE(d), SUM(c)
FROM (
  SELECT  a.end_time as d, a.calories as c
  FROM activities a
  JOIN user_activities uc ON uc.activity_id = a.id
  WHERE uc.user_id = 1
  AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 6 DAY
  UNION ALL
  SELECT CURRENT_DATE, 0
  UNION ALL
  SELECT CURRENT_DATE - INTERVAL 1 DAY, 0
  UNION ALL
  SELECT CURRENT_DATE - INTERVAL 2 DAY, 0
  UNION ALL
  SELECT CURRENT_DATE - INTERVAL 3 DAY, 0
  UNION ALL
  SELECT CURRENT_DATE - INTERVAL 4 DAY, 0
  UNION ALL
  SELECT CURRENT_DATE - INTERVAL 5 DAY, 0
  UNION ALL
  SELECT CURRENT_DATE - INTERVAL 6 DAY, 0
) z
GROUP BY DATE(d)

fa06的方法依赖于活动表中每天有一条记录。这是解决问题的有效方法,但是您还没有具体说明这些表包含哪些数据(提示:发布数据库问题时,请务必包括每个表的示例数据)

使用这种方法,我们可以像往常一样进行查找,但是我们还会生成7个伪造的行,这些行的日期为最近7天,卡路里计数为0。当添加到真实的卡路里计数中时,这些不含脂肪;),并且当没有特定日期的数据时,它们单独提供0

如果您希望有更多的日子,请考虑转到行生成模式。 MySQL没有其他数据库那样的行生成器,但是最简单的技巧是创建  变量,将其初始化为0,然后递增,并在至少包含30行的表返回的每一行中使用它:

SELECT CURRENT_DATE - INTERVAL (@row := @row + 1) DAY as dt, 0 as cal
FROM activities t, (SELECT @row := -1) r
LIMIT 30

其背后的理论是:该表至少有30行,@ row变量被初始化为-1,并且在整个查询范围内都存在。当将行拉出并返回时,@row递增,然后返回(所以它是0、1、2 ..),并且此递增的计数用于从当前数据中减去0、1、2等天,给我们一个过去30天的日期顺序

SELECT DATE(d), SUM(c)
FROM (
  SELECT  a.end_time as d, a.calories as c
  FROM activities a
  JOIN user_activities uc ON uc.activity_id = a.id
  WHERE uc.user_id = 1
  AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 29 DAY
  UNION ALL

  SELECT CURRENT_DATE - INTERVAL (@row := @row + 1) DAY as dt, 0 as cal
  FROM activities t, (SELECT @row := -1) r
  WHERE @row < 30
) z
GROUP BY DATE(d)

请注意,我无法测试这两个查询。第二个可能有一些小的语法错误。如果事实证明这行不通,并且错误不平凡/您无法修复的问题,请通知我。

调试:

单独运行这些查询。我不知道它将产生多少行:

  SELECT  a.end_time as d, a.calories as c
  FROM activities a
  JOIN user_activities uc ON uc.activity_id = a.id
  WHERE uc.user_id = 1
  AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 29 DAY

这应该产生30行。如果不是,那是因为您没有使用至少包含30行的表:

  SELECT CURRENT_DATE - INTERVAL (@row := @row + 1) DAY as dt, 0 as cal
  FROM activities t, (SELECT @row := -1) r
  LIMIT 30

编辑:

已修复此错误-合并后应用了LIMIT;这会产生不良结果

答案 2 :(得分:0)

我正在尝试,只是将SUM(a.calories)更新为IF(SUM(a.calories) IS NULL, 0, SUM(a.calories))

您可以在这里尝试...

SELECT  DATE(a.end_time), IF(SUM(a.calories) IS NULL, 0, SUM(a.calories))
  FROM activities a
    JOIN user_activities uc ON uc.activity_id = a.id
  WHERE uc.user_id = 1
    AND
     DATE(a.end_time) >= CURRENT_DATE - INTERVAL 6 DAY
  GROUP BY DATE(a.end_time) DESC

答案 3 :(得分:0)

此查询应达到目的:

  • CTE动态生成日期范围(这可能会提前300年)
  • 结果与LEFT JOINactivitiesuser_activities COALESCE函数将空的SUM转换为0个值

查询:

WITH v AS (
    SELECT * FROM 
        (SELECT adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) selected_date FROM
        (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t0,
        (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1,
        (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2,
        (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3,
        (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t4) v
    WHERE selected_date BETWEEN CURRENT_DATE - INTERVAL 6 DAY AND CURRENT_DATE
)
SELECT v.selected_date, COALESCE(SUM(a.calories), 0)
FROM 
    v
    LEFT JOIN activities a on DATE(a.end_time) = v.selected_date
    LEFT JOIN user_activities uc ON uc.activity_id = a.id AND uc.user_id = 1
GROUP BY DATE(a.end_time) DESC
ORDER BY v.selected_date