左联接的SQL Null为0?

时间:2018-08-19 16:41:51

标签: mysql sql

问题

我有一个日志表,用户可以在其中输入在一个项目上花费了多少小时。 (它用于应用程序上的图形和数据表)。我还生成了一个“日历”表,因此我可以保留加入日期,并用零填充“空”日期。但是,花了一些时间之后,我找不到办法了...

表1:日志

id | hoursSpent | logDate 
1    5            2018-08-05
2    1            2018-08-07
3    3            2018-08-10

表2:日历

id         | db_date
20180807     2018-08-07
20180808     2018-08-08
20180809     2018-08-09
201808010    2018-08-10
etc...

所需的输出

db_date      | hoursSpent
2018-08-05     5
2018-08-06     0
2018-08-07     1
2018-08-08     0
2018-08-09     0
2018-08-10     3

到目前为止已使用的代码(无法完全正常运行...)

SELECT hoursSpent, db_date
FROM logs LEFT JOIN calendar ON db_date
WHERE db_date BETWEEN '2018-08-10' AND '2018-08-01'
GROUP BY db_date

3 个答案:

答案 0 :(得分:0)

使用LEFT JOIN是正确的。查询的其余部分需要清理:

SELECT c.db_date, COALESCE(l.hoursSpent, 0) as hoursSpent
FROM calendar c LEFT JOIN
     logs l
     ON c.db_date = l.logdate
WHERE c.db_date BETWEEN '2018-08-01' AND '2018-08-10';

注意:

  • 您需要calendar中的所有行,因此它应该是LEFT JOIN中的第一张表。
  • 您需要有效的ON条件来连接两个表。
  • BETWEEN要求操作数是按顺序排列的,因此较小的是在AND之前,较大的是在之后。
  • GROUP BY似乎是不必要的。
    • COALESCE()实际上生成了0值。
  • 在具有多个表引用的查询中,限定所有列名称。

答案 1 :(得分:0)

您的加入顺序错误,calendar应该在左侧,因为无论logs中是否有匹配的行都应包含其所有行。要将NULL转换为0,请使用coalesce()。而且,如果您GROUP BY日期,则必须在hoursspent上应用聚合函数。我猜你想sum()

SELECT c.db_date,
       sum(coalesce(l.hoursspent, 0)) hoursspent
       FROM calendar c
            LEFT JOIN logs l
                      ON l.logdate = c.db_date
       WHERE c.db_date BETWEEN '2018-08-10'
                               AND '2018-08-01'
       GROUP BY c.db_date;

在这里您还可以省略coalesce(),因为MySQL的sum()仍然将NULL视为0

但是样本数据表明,如果同一天的日志条目不超过一个,那么您可能根本不需要GROUP BY

SELECT c.db_date,
       coalesce(l.hoursspent, 0) hoursspent
       FROM calendar c
            LEFT JOIN logs l
                      ON l.logdate = c.db_date
       WHERE c.db_date BETWEEN '2018-08-10'
                               AND '2018-08-01';

答案 2 :(得分:0)

具有所有必需行(Calendar)的表必须位于LEFT JOIN的左侧,而缺少记录(Logs)的表必须位于右侧。另外,您可以保持表格顺序,而使用RIGHT JOIN

当查询中有多个表时,使用别名消除歧义很有用。

完整的ON子句需要进行比较。

BETWEEN条件中指定的范围必须按升序排列。

GROUP BY子句要求您将聚合函数应用于SELECT列表中的所有非分组表达式。这里的SUM函数是合适的。由于如果没有匹配的记录,SUM函数将返回NULL s,因此我们应用COALESCE函数将它们转换为0 s。

SELECT
    c.db_date, COALESCE(SUM(l.hoursSpent), 0) AS hoursSpent
FROM
    Calendar c
    LEFT JOIN Logs l
        ON c.db_date = l.logDate
WHERE
    c.db_date BETWEEN '2018-08-01' AND '2018-08-10'        
GROUP BY
    c.db_date;

请参见SQL提琴:http://sqlfiddle.com/#!9/d28de9c/3/0