0

我的查询有点生疏......我一直在努力获得所需的结果一段时间。已尝试先搜索,但也许我没有搜索正确的术语。

我有一个人员表和一个小时表。我试图得到这样的结果:

name    mon     tue     wed     thu     fri     total
Bob     15      8.5     9.25    8.75    15      56.5
Joe     10.5    0       0       0       0       10.5

这是我目前的查询:

SELECT e.name,m.mon,t.tue,w.wed,th.thu,f.fri,sum(m.mon+t.tue+w.wed+th.thu+f.fri) as total 
FROM people e 
JOIN (SELECT uid, round(((TIME_TO_SEC(tout) - TIME_TO_SEC(tin))/60)/60,2) AS mon FROM vhours WHERE DAYNAME(wdate)='Monday' AND YEARWEEK(wdate)=YEARWEEK(NOW())) as m ON m.uid=e.id 
JOIN (SELECT uid, round(((TIME_TO_SEC(tout) - TIME_TO_SEC(tin))/60)/60,2) AS tue FROM vhours WHERE DAYNAME(wdate)='Tuesday' AND YEARWEEK(wdate)=YEARWEEK(NOW())) as t ON t.uid=e.id 
JOIN (SELECT uid, round(((TIME_TO_SEC(tout) - TIME_TO_SEC(tin))/60)/60,2) AS wed FROM vhours WHERE DAYNAME(wdate)='Wednesday' AND YEARWEEK(wdate)=YEARWEEK(NOW())) as w ON w.uid=e.id 
JOIN (SELECT uid, round(((TIME_TO_SEC(tout) - TIME_TO_SEC(tin))/60)/60,2) AS thu FROM vhours WHERE DAYNAME(wdate)='Thursday' AND YEARWEEK(wdate)=YEARWEEK(NOW())) as th ON th.uid=e.id 
JOIN (SELECT uid, round(((TIME_TO_SEC(tout) - TIME_TO_SEC(tin))/60)/60,2) AS fri FROM vhours WHERE DAYNAME(wdate)='Friday' AND YEARWEEK(wdate)=YEARWEEK(NOW())) as f ON f.uid=e.id

但是,只有当人员每天都有小时数时,查询才会产生结果。如果他们没有每天的工作时间,他们的工作时间就根本不会出现。

这是一个 SQL 小提琴:http ://sqlfiddle.com/#!9/4ac3cd/1

4

2 回答 2

2

您只需要 1 个表连接和条件聚合:

SELECT p.name,
  COALESCE(SUM(CASE WHEN DAYNAME(v.wdate)='Monday' THEN round(((TIME_TO_SEC(v.tout) - TIME_TO_SEC(v.tin))/60)/60,2) END), 0) mon,
  COALESCE(SUM(CASE WHEN DAYNAME(v.wdate)='Tuesday' THEN round(((TIME_TO_SEC(v.tout) - TIME_TO_SEC(v.tin))/60)/60,2) END), 0) tue,
  COALESCE(SUM(CASE WHEN DAYNAME(v.wdate)='Wednesday' THEN round(((TIME_TO_SEC(v.tout) - TIME_TO_SEC(v.tin))/60)/60,2) END), 0) wed,
  COALESCE(SUM(CASE WHEN DAYNAME(v.wdate)='Thursday' THEN round(((TIME_TO_SEC(v.tout) - TIME_TO_SEC(v.tin))/60)/60,2) END), 0) thu,
  COALESCE(SUM(CASE WHEN DAYNAME(v.wdate)='Friday' THEN round(((TIME_TO_SEC(v.tout) - TIME_TO_SEC(v.tin))/60)/60,2) END), 0) frid,
  COALESCE(SUM(round(((TIME_TO_SEC(v.tout) - TIME_TO_SEC(v.tin))/60)/60,2)), 0) Total
FROM people p LEFT JOIN vhours v
ON v.uid = p.id AND YEARWEEK(v.wdate)=YEARWEEK(NOW()) AND DAYOFWEEK(v.wdate) BETWEEN 2 AND 6   
GROUP BY p.id, p.name

请参阅演示
甚至更好:

SELECT p.name,
  COALESCE(SUM(CASE WHEN v.day = 'Monday' THEN v.hours END), 0) mon,
  COALESCE(SUM(CASE WHEN v.day = 'Tuesday' THEN v.hours END), 0) tue,
  COALESCE(SUM(CASE WHEN v.day = 'Wednesday' THEN v.hours END), 0) wed,
  COALESCE(SUM(CASE WHEN v.day = 'Thursday' THEN v.hours END), 0) thu,
  COALESCE(SUM(CASE WHEN v.day = 'Friday' THEN v.hours END), 0) fri,
  COALESCE(SUM(v.hours), 0) Total
FROM people p LEFT JOIN (
  SELECT uid, DAYNAME(wdate) day,
    ROUND(TIMESTAMPDIFF(SECOND, tin, tout) / 3600, 2) hours
  FROM vhours 
  WHERE YEARWEEK(wdate) = YEARWEEK(NOW()) AND DAYOFWEEK(wdate) BETWEEN 2 AND 6
) v
ON v.uid = p.id 
GROUP BY p.id, p.name

请参阅演示
结果:

| name | mon | tue | wed  | thu  | fri  | Total |
| ---- | --- | --- | ---- | ---- | ---- | ----- |
| Bob  | 15  | 8.5 | 9.25 | 8.75 | 15   | 56.5  |
| Joe  | 0   | 11  | 0    | 0    | 0    | 11    |
| Dan  | 0   | 0   | 0    | 10.5 | 0    | 10.5  |
| Carl | 0   | 0   | 0    | 0    | 0    | 0     |
于 2020-03-26T23:23:28.547 回答
0

使用LEFT JOIN而不是JOIN. 这将为所有不匹配的行返回空值,您可以使用IFNULL()它们将它们转换为0.

不要使用SUM(). 那是为了跨行求和,当您将列添加在一起时不需要它。只需使用+所有列名即可完成。

SELECT e.name,IFNULL(m.mon, 0) mon,IFNULL(t.tue, 0) tue, IFNULL(w.wed, 0) wed, IFNULL(th.thu, 0) thu, IFNULL(f.fri, 0) fri,
      IFNULL(m.mon, 0)+IFNULL(t.tue, 0)+IFNULL(w.wed, 0)+IFNULL(th.thu, 0)+IFNULL(f.fri, 0) as total 
FROM people e 
LEFT JOIN (SELECT uid, round(((TIME_TO_SEC(tout) - TIME_TO_SEC(tin))/60)/60,2) AS mon FROM vhours WHERE DAYNAME(wdate)='Monday' AND YEARWEEK(wdate)=YEARWEEK(NOW())) as m ON m.uid=e.id 
LEFT JOIN (SELECT uid, round(((TIME_TO_SEC(tout) - TIME_TO_SEC(tin))/60)/60,2) AS tue FROM vhours WHERE DAYNAME(wdate)='Tuesday' AND YEARWEEK(wdate)=YEARWEEK(NOW())) as t ON t.uid=e.id 
LEFT JOIN (SELECT uid, round(((TIME_TO_SEC(tout) - TIME_TO_SEC(tin))/60)/60,2) AS wed FROM vhours WHERE DAYNAME(wdate)='Wednesday' AND YEARWEEK(wdate)=YEARWEEK(NOW())) as w ON w.uid=e.id 
LEFT JOIN (SELECT uid, round(((TIME_TO_SEC(tout) - TIME_TO_SEC(tin))/60)/60,2) AS thu FROM vhours WHERE DAYNAME(wdate)='Thursday' AND YEARWEEK(wdate)=YEARWEEK(NOW())) as th ON th.uid=e.id 
LEFT JOIN (SELECT uid, round(((TIME_TO_SEC(tout) - TIME_TO_SEC(tin))/60)/60,2) AS fri FROM vhours WHERE DAYNAME(wdate)='Friday' AND YEARWEEK(wdate)=YEARWEEK(NOW())) as f ON f.uid=e.id

演示

于 2020-03-26T23:21:42.660 回答