SQL 按行到列的数据透视组
SQL Pivot group by rows to columns
所以我有一个 table 用于我想每天计算的司机活动。
示例数据:
Name
StartDateAndTime
EndDateAndTime
StartText
EndText
WorkState
Jim
2021-09-09 06:28:16
2021-09-09 07:28:16
"StartPlace0"
"EndPlace0"
"Pause"
Jim
2021-09-09 07:28:16
2021-09-09 08:28:16
"StartPlace1"
"EndPlace1"
"Loading"
Jim
2021-09-09 08:28:16
2021-09-09 09:28:16
"StartPlace2"
"EndPlace2"
"Driving"
Jim
2021-09-09 10:28:16
2021-09-09 11:28:16
"StartPlace4"
"EndPlace4"
"Loading"
Jim
2021-10-09 09:28:16
2021-10-09 10:28:16
"StartPlace5"
"EndPlace5"
"Driving"
Jim
2021-10-09 10:28:16
2021-10-09 11:28:16
"StartPlace6"
"EndPlace6"
"Loading"
Jim
2021-10-09 11:28:16
2021-10-09 14:28:16
"StartPlace7"
"EndPlace7"
"Driving"
期望的输出:(我只有 3 种可能的工作状态)
Name
StartDateAndTime
EndDateAndTime
StartText
EndText
Loading
Driving
Jim
2021-09-09 06:28:16
2021-09-09 11:28:16
"StartPlace0"
"EndPlace4"
00:02:00
00:01:00
Jim
2021-10-09 09:28:16
2021-09-09 14:28:16
"StartPlace5"
"EndPlace7"
00:01:00
00:04:00
Pause
DayPerformed
00:01:00
2021-09-09
00:00:00
2021-10-09
到目前为止我的看法:(摘要)
--CREATE view vwWorkingTimesPerDay as
select
w.DriverName,
convert(date, w.StartDateAndTime) as DayPerformed,
MIN(w.StartDateAndTime) as StartTime,
MAX(w.EndDateAndTime) as EndTime,
StartPositionText,
EndPositionText
from (
SELECT *,
StartPositionText = FIRST_VALUE(StartPosText) OVER (PARTITION BY w.DriverName, convert(date,
w.StartDateAndTime)
ORDER BY w.StartDateAndTime ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),
EndPositionText = LAST_VALUE(EndPosText) OVER (PARTITION BY w.DriverName, convert(date,
w.StartDateAndTime)
ORDER BY w.StartDateAndTime ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM webfleet.tblWorkingTimes w) w
group by w.DriverName,
convert(date, w.StartDateAndTime),
StartPositionText,
EndPositionText,
为了显示原始 table 中的持续时间,我使用了:
right('00' + convert(varchar, datepart(hour, dateadd(s, sum(datediff(second,
w.StartDateAndTime, w.EndDateAndTime)), 0))), 2) + ':'
+ right('00' + convert(varchar, datepart(minute, dateadd(s, sum(datediff(second,
w.StartDateAndTime, w.EndDateAndTime)), 0))), 2) + ':'
+ right('00' + convert(varchar, datepart(second, dateadd(s, sum(datediff(second,
w.StartDateAndTime, w.EndDateAndTime)), 0))), 2)
as Duration
我试过这篇文章https://www.sqlshack.com/multiple-options-to-transposing-rows-into-columns
但我没有足够的经验来使用这些选项。
我想要的数据顺序并不重要,如果有更好的方法来计算和显示持续时间,我很高兴听到。
这需要几个步骤
- 我们使用
CAST AS date
来获取没有时间的日期
ROW_NUMBER
和LEAD
帮助我们识别每个分组的开始和结束
- 然后简单地按
Name
和日期 汇总
- 并使用条件聚合得到我们想要的结果
- 要获得时间值,我们将秒数加到
0:00:00
时间
SELECT
Name,
DayPerformed,
StartDateAndTime = MIN(StartDateAndTime),
EndDateAndTime = MAX(EndDateAndTime),
StartText = MIN(CASE WHEN rn = 1 THEN StartText END),
EndText = MIN(CASE WHEN nxt IS NULL THEN EndText END),
Loading = DATEADD(ms,
ISNULL(SUM(CASE WHEN WorkState = 'Loading' THEN DATEDIFF(ms, StartDateAndTime, EndDateAndTime) END), 0),
CAST('0:00:00' AS time)),
Driving = DATEADD(ms,
ISNULL(SUM(CASE WHEN WorkState = 'Driving' THEN DATEDIFF(ms, StartDateAndTime, EndDateAndTime) END), 0),
CAST('0:00:00' AS time)),
Pause = DATEADD(ms,
ISNULL(SUM(CASE WHEN WorkState = 'Pause' THEN DATEDIFF(ms, StartDateAndTime, EndDateAndTime) END), 0),
CAST('0:00:00' AS time))
FROM (
SELECT *,
rn = ROW_NUMBER() OVER (PARTITION BY Name, DayPerformed ORDER BY StartDateAndTime),
nxt = LEAD(WorkState) OVER (PARTITION BY Name, DayPerformed ORDER BY StartDateAndTime)
FROM tblWorkingTimes wt
CROSS APPLY (VALUES (CAST(StartDateAndTime AS date))) v(DayPerformed)
) wt
GROUP BY
Name,
DayPerformed;
要按月汇总,只需将 DayPerformed
替换为
CROSS APPLY (VALUES (EOMONTH(StartDateAndTime))) v(DayPerformed)
所以我有一个 table 用于我想每天计算的司机活动。 示例数据:
Name | StartDateAndTime | EndDateAndTime | StartText | EndText | WorkState |
---|---|---|---|---|---|
Jim | 2021-09-09 06:28:16 | 2021-09-09 07:28:16 | "StartPlace0" | "EndPlace0" | "Pause" |
Jim | 2021-09-09 07:28:16 | 2021-09-09 08:28:16 | "StartPlace1" | "EndPlace1" | "Loading" |
Jim | 2021-09-09 08:28:16 | 2021-09-09 09:28:16 | "StartPlace2" | "EndPlace2" | "Driving" |
Jim | 2021-09-09 10:28:16 | 2021-09-09 11:28:16 | "StartPlace4" | "EndPlace4" | "Loading" |
Jim | 2021-10-09 09:28:16 | 2021-10-09 10:28:16 | "StartPlace5" | "EndPlace5" | "Driving" |
Jim | 2021-10-09 10:28:16 | 2021-10-09 11:28:16 | "StartPlace6" | "EndPlace6" | "Loading" |
Jim | 2021-10-09 11:28:16 | 2021-10-09 14:28:16 | "StartPlace7" | "EndPlace7" | "Driving" |
期望的输出:(我只有 3 种可能的工作状态)
Name | StartDateAndTime | EndDateAndTime | StartText | EndText | Loading | Driving |
---|---|---|---|---|---|---|
Jim | 2021-09-09 06:28:16 | 2021-09-09 11:28:16 | "StartPlace0" | "EndPlace4" | 00:02:00 | 00:01:00 |
Jim | 2021-10-09 09:28:16 | 2021-09-09 14:28:16 | "StartPlace5" | "EndPlace7" | 00:01:00 | 00:04:00 |
Pause | DayPerformed |
---|---|
00:01:00 | 2021-09-09 |
00:00:00 | 2021-10-09 |
到目前为止我的看法:(摘要)
--CREATE view vwWorkingTimesPerDay as
select
w.DriverName,
convert(date, w.StartDateAndTime) as DayPerformed,
MIN(w.StartDateAndTime) as StartTime,
MAX(w.EndDateAndTime) as EndTime,
StartPositionText,
EndPositionText
from (
SELECT *,
StartPositionText = FIRST_VALUE(StartPosText) OVER (PARTITION BY w.DriverName, convert(date,
w.StartDateAndTime)
ORDER BY w.StartDateAndTime ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),
EndPositionText = LAST_VALUE(EndPosText) OVER (PARTITION BY w.DriverName, convert(date,
w.StartDateAndTime)
ORDER BY w.StartDateAndTime ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM webfleet.tblWorkingTimes w) w
group by w.DriverName,
convert(date, w.StartDateAndTime),
StartPositionText,
EndPositionText,
为了显示原始 table 中的持续时间,我使用了:
right('00' + convert(varchar, datepart(hour, dateadd(s, sum(datediff(second,
w.StartDateAndTime, w.EndDateAndTime)), 0))), 2) + ':'
+ right('00' + convert(varchar, datepart(minute, dateadd(s, sum(datediff(second,
w.StartDateAndTime, w.EndDateAndTime)), 0))), 2) + ':'
+ right('00' + convert(varchar, datepart(second, dateadd(s, sum(datediff(second,
w.StartDateAndTime, w.EndDateAndTime)), 0))), 2)
as Duration
我试过这篇文章https://www.sqlshack.com/multiple-options-to-transposing-rows-into-columns
但我没有足够的经验来使用这些选项。 我想要的数据顺序并不重要,如果有更好的方法来计算和显示持续时间,我很高兴听到。
这需要几个步骤
- 我们使用
CAST AS date
来获取没有时间的日期 ROW_NUMBER
和LEAD
帮助我们识别每个分组的开始和结束- 然后简单地按
Name
和日期 汇总
- 并使用条件聚合得到我们想要的结果
- 要获得时间值,我们将秒数加到
0:00:00
时间
SELECT
Name,
DayPerformed,
StartDateAndTime = MIN(StartDateAndTime),
EndDateAndTime = MAX(EndDateAndTime),
StartText = MIN(CASE WHEN rn = 1 THEN StartText END),
EndText = MIN(CASE WHEN nxt IS NULL THEN EndText END),
Loading = DATEADD(ms,
ISNULL(SUM(CASE WHEN WorkState = 'Loading' THEN DATEDIFF(ms, StartDateAndTime, EndDateAndTime) END), 0),
CAST('0:00:00' AS time)),
Driving = DATEADD(ms,
ISNULL(SUM(CASE WHEN WorkState = 'Driving' THEN DATEDIFF(ms, StartDateAndTime, EndDateAndTime) END), 0),
CAST('0:00:00' AS time)),
Pause = DATEADD(ms,
ISNULL(SUM(CASE WHEN WorkState = 'Pause' THEN DATEDIFF(ms, StartDateAndTime, EndDateAndTime) END), 0),
CAST('0:00:00' AS time))
FROM (
SELECT *,
rn = ROW_NUMBER() OVER (PARTITION BY Name, DayPerformed ORDER BY StartDateAndTime),
nxt = LEAD(WorkState) OVER (PARTITION BY Name, DayPerformed ORDER BY StartDateAndTime)
FROM tblWorkingTimes wt
CROSS APPLY (VALUES (CAST(StartDateAndTime AS date))) v(DayPerformed)
) wt
GROUP BY
Name,
DayPerformed;
要按月汇总,只需将 DayPerformed
替换为
CROSS APPLY (VALUES (EOMONTH(StartDateAndTime))) v(DayPerformed)