我有一个日志表,用户可以在其中输入在一个项目上花费了多少小时。 (它用于应用程序上的图形和数据表)。我还生成了一个“日历”表,因此我可以保留加入日期,并用零填充“空”日期。但是,花了一些时间之后,我找不到办法了...
id | hoursSpent | logDate
1 5 2018-08-05
2 1 2018-08-07
3 3 2018-08-10
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
答案 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