SQL 总和列由其他 "dislocated" 列汇总
SQL sum columns aggregate by others "dislocated" columns
如果你能帮我解决这个问题,我将不胜感激。
我有这个 Oracle SQL 查询的结果,是关于夜班时间表的。
start_day_hours 是轮班 start_date 和午夜之间的总工作时间。
end_day_hours 是从午夜到轮班结束之间的总工作时间。
start midnight end start_day_hours end_day_hours
02/10/17 21:33 02/10/17 23:59 03/10/17 00:42 2,43 0,71
03/10/17 21:34 03/10/17 23:59 04/10/17 00:19 2,42 0,32
04/10/17 21:59 04/10/17 23:59 05/10/17 55:36 2,00 0,92
16/10/17 21:59 16/10/17 23:59 17/10/17 00:01 2,00 0,01
18/10/17 22:50 18/10/17 23:59 19/10/17 00:25 1,16 0,42
19/10/17 22:19 19/10/17 23:59 20/10/17 01:00 1,67 1,01
我每天需要 start_day_hours 和 end_day_hours 的总和,例如:
day total_hours
02/10/17 2,43 (2,43)
03/10/17 3,13 (0.71+2,42)
04/10/17 2,32 (0.32+2.00)
05/10/17 0,92 (0,92)
16/10/17 2,00 (2,00)
17/10/17 0,01 (0,01)
18/10/17 1,16 (1,16)
19/10/17 2,51 (0.42+1.67)
20/10/17 1,01 (1,01)
非常感谢您的帮助!
Oracle 11g R2 架构设置:
CREATE TABLE shift (
"start" DATE,
"end" DATE
);
INSERT INTO shift
SELECT TIMESTAMP '2017-10-02 21:33:00', TIMESTAMP '2017-10-03 00:42:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2017-10-03 21:34:00', TIMESTAMP '2017-10-04 00:19:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2017-10-04 21:59:00', TIMESTAMP '2017-10-05 00:55:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2017-10-16 21:59:00', TIMESTAMP '2017-10-17 00:01:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2017-10-18 22:50:00', TIMESTAMP '2017-10-19 00:25:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2017-10-19 22:19:00', TIMESTAMP '2017-10-20 01:00:00' FROM DUAL;
查询 1:
使用行生成器获取最早 start
和最晚 end
之间的每一天,然后在这一天与班次重叠时将其加入原始 table 并聚合这些重叠:
WITH days ( dt ) AS (
SELECT min_dt + LEVEL - 1
FROM (
SELECT TRUNC( MIN( "start" ) ) AS min_dt,
TRUNC( MAX( "end" ) ) AS max_dt
FROM shift
)
CONNECT BY min_dt + LEVEL - 1 <= max_dt
)
SELECT dt,
SUM(
LEAST( "end", dt + INTERVAL '1' DAY )
- GREATEST( "start", dt )
) * 24 AS hours_worked
FROM shift s
INNER JOIN days d
ON ( s."start" < d.dt + INTERVAL '1' DAY
AND s."end" > d.dt )
GROUP BY dt
ORDER BY dt
| DT | HOURS_WORKED |
|----------------------|----------------------|
| 2017-10-02T00:00:00Z | 2.45 |
| 2017-10-03T00:00:00Z | 3.1333333333333333 |
| 2017-10-04T00:00:00Z | 2.3333333333333335 |
| 2017-10-05T00:00:00Z | 0.9166666666666666 |
| 2017-10-16T00:00:00Z | 2.0166666666666666 |
| 2017-10-17T00:00:00Z | 0.016666666666666666 |
| 2017-10-18T00:00:00Z | 1.1666666666666667 |
| 2017-10-19T00:00:00Z | 2.1 |
| 2017-10-20T00:00:00Z | 1 |
SELECT T1.START_DATE,nvl(T1.START_DAY_HOURS,0) + nvl(T2.END_DAY_HOURS,0) TOTAL_HOURS
FROM
(SELECT TRUNC(START) START_DATE,sum(nvl(START_DAY_HOURS,0)) START_DAY_HOURS FROM YOUR_TABLE GROUP BY TRUNC(START)) T1
LEFT JOIN (SELECT TRUNC(END) END_DATE,SUM(nvl(END_DAY_HOURS,0)) END_DAY_HOURS FROM YOUR_TABLE GROUP BY TRUNC(END)) T2
ON T1.START_DATE = T2.END_DATE
一种简单的方法是将 start/end date
并入 1 列,将 start_hours/end_hours
并入另一列,trunc
date
列,group by
日期并计算sum
hours
列如下。
SELECT date1 AS DAY,
sum(hours) AS total_hours
FROM
(SELECT trunc(start1) AS date1,
start_day_hours AS hours
FROM t1
UNION ALL
SELECT trunc(end1),
end_day_hours
FROM t1 ) t
GROUP BY date1
ORDER BY date1;
结果:
DAY TOTAL_HOURS
---------------------------------
02.10.2017 00:00:00 2,43
03.10.2017 00:00:00 3,13
04.10.2017 00:00:00 2,32
05.10.2017 00:00:00 0,92
16.10.2017 00:00:00 2
17.10.2017 00:00:00 0,01
18.10.2017 00:00:00 1,16
19.10.2017 00:00:00 2,09
20.10.2017 00:00:00 1,01
非常感谢@MT0 的帮助。我终于做到了:
SELECT dt,
NVL(SUM(
LEAST( SIXTY, dt + INTERVAL '1' DAY )
- GREATEST( ZERO, dt )
) * 24, 0.0) AS hours_worked
FROM shitf s
RIGHT JOIN
(SELECT TO_DATE('2017-10-01 00:00:00', 'YYYY/MM/DD HH24:MI:SS')+LEVEL-1 AS dt
FROM DUAL CONNECT BY LEVEL <= TO_CHAR(LAST_DAY(TO_DATE('2017-10-01 00:00:00', 'YYYY/MM/DD HH24:MI:SS')),'DD')) d
ON (s.ZERO < d.dt + INTERVAL '1' DAY
AND s.SIXTY > d.dt )
GROUP dt
ORDER dt
如果你能帮我解决这个问题,我将不胜感激。
我有这个 Oracle SQL 查询的结果,是关于夜班时间表的。
start_day_hours 是轮班 start_date 和午夜之间的总工作时间。 end_day_hours 是从午夜到轮班结束之间的总工作时间。
start midnight end start_day_hours end_day_hours
02/10/17 21:33 02/10/17 23:59 03/10/17 00:42 2,43 0,71
03/10/17 21:34 03/10/17 23:59 04/10/17 00:19 2,42 0,32
04/10/17 21:59 04/10/17 23:59 05/10/17 55:36 2,00 0,92
16/10/17 21:59 16/10/17 23:59 17/10/17 00:01 2,00 0,01
18/10/17 22:50 18/10/17 23:59 19/10/17 00:25 1,16 0,42
19/10/17 22:19 19/10/17 23:59 20/10/17 01:00 1,67 1,01
我每天需要 start_day_hours 和 end_day_hours 的总和,例如:
day total_hours
02/10/17 2,43 (2,43)
03/10/17 3,13 (0.71+2,42)
04/10/17 2,32 (0.32+2.00)
05/10/17 0,92 (0,92)
16/10/17 2,00 (2,00)
17/10/17 0,01 (0,01)
18/10/17 1,16 (1,16)
19/10/17 2,51 (0.42+1.67)
20/10/17 1,01 (1,01)
非常感谢您的帮助!
Oracle 11g R2 架构设置:
CREATE TABLE shift (
"start" DATE,
"end" DATE
);
INSERT INTO shift
SELECT TIMESTAMP '2017-10-02 21:33:00', TIMESTAMP '2017-10-03 00:42:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2017-10-03 21:34:00', TIMESTAMP '2017-10-04 00:19:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2017-10-04 21:59:00', TIMESTAMP '2017-10-05 00:55:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2017-10-16 21:59:00', TIMESTAMP '2017-10-17 00:01:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2017-10-18 22:50:00', TIMESTAMP '2017-10-19 00:25:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2017-10-19 22:19:00', TIMESTAMP '2017-10-20 01:00:00' FROM DUAL;
查询 1:
使用行生成器获取最早 start
和最晚 end
之间的每一天,然后在这一天与班次重叠时将其加入原始 table 并聚合这些重叠:
WITH days ( dt ) AS (
SELECT min_dt + LEVEL - 1
FROM (
SELECT TRUNC( MIN( "start" ) ) AS min_dt,
TRUNC( MAX( "end" ) ) AS max_dt
FROM shift
)
CONNECT BY min_dt + LEVEL - 1 <= max_dt
)
SELECT dt,
SUM(
LEAST( "end", dt + INTERVAL '1' DAY )
- GREATEST( "start", dt )
) * 24 AS hours_worked
FROM shift s
INNER JOIN days d
ON ( s."start" < d.dt + INTERVAL '1' DAY
AND s."end" > d.dt )
GROUP BY dt
ORDER BY dt
| DT | HOURS_WORKED |
|----------------------|----------------------|
| 2017-10-02T00:00:00Z | 2.45 |
| 2017-10-03T00:00:00Z | 3.1333333333333333 |
| 2017-10-04T00:00:00Z | 2.3333333333333335 |
| 2017-10-05T00:00:00Z | 0.9166666666666666 |
| 2017-10-16T00:00:00Z | 2.0166666666666666 |
| 2017-10-17T00:00:00Z | 0.016666666666666666 |
| 2017-10-18T00:00:00Z | 1.1666666666666667 |
| 2017-10-19T00:00:00Z | 2.1 |
| 2017-10-20T00:00:00Z | 1 |
SELECT T1.START_DATE,nvl(T1.START_DAY_HOURS,0) + nvl(T2.END_DAY_HOURS,0) TOTAL_HOURS
FROM
(SELECT TRUNC(START) START_DATE,sum(nvl(START_DAY_HOURS,0)) START_DAY_HOURS FROM YOUR_TABLE GROUP BY TRUNC(START)) T1
LEFT JOIN (SELECT TRUNC(END) END_DATE,SUM(nvl(END_DAY_HOURS,0)) END_DAY_HOURS FROM YOUR_TABLE GROUP BY TRUNC(END)) T2
ON T1.START_DATE = T2.END_DATE
一种简单的方法是将 start/end date
并入 1 列,将 start_hours/end_hours
并入另一列,trunc
date
列,group by
日期并计算sum
hours
列如下。
SELECT date1 AS DAY,
sum(hours) AS total_hours
FROM
(SELECT trunc(start1) AS date1,
start_day_hours AS hours
FROM t1
UNION ALL
SELECT trunc(end1),
end_day_hours
FROM t1 ) t
GROUP BY date1
ORDER BY date1;
结果:
DAY TOTAL_HOURS
---------------------------------
02.10.2017 00:00:00 2,43
03.10.2017 00:00:00 3,13
04.10.2017 00:00:00 2,32
05.10.2017 00:00:00 0,92
16.10.2017 00:00:00 2
17.10.2017 00:00:00 0,01
18.10.2017 00:00:00 1,16
19.10.2017 00:00:00 2,09
20.10.2017 00:00:00 1,01
非常感谢@MT0 的帮助。我终于做到了:
SELECT dt,
NVL(SUM(
LEAST( SIXTY, dt + INTERVAL '1' DAY )
- GREATEST( ZERO, dt )
) * 24, 0.0) AS hours_worked
FROM shitf s
RIGHT JOIN
(SELECT TO_DATE('2017-10-01 00:00:00', 'YYYY/MM/DD HH24:MI:SS')+LEVEL-1 AS dt
FROM DUAL CONNECT BY LEVEL <= TO_CHAR(LAST_DAY(TO_DATE('2017-10-01 00:00:00', 'YYYY/MM/DD HH24:MI:SS')),'DD')) d
ON (s.ZERO < d.dt + INTERVAL '1' DAY
AND s.SIXTY > d.dt )
GROUP dt
ORDER dt