MS SQL按状态获取聚合日期时间差
我有下面的sql表MS SQL按状态获取聚合日期时间差,sql,sql-server,Sql,Sql Server,我有下面的sql表 ====================================================== UnitID Status DateTime Value ====================================================== 101 A 01/12/2017 00:02:10 10 101 A 01/12
======================================================
UnitID Status DateTime Value
======================================================
101 A 01/12/2017 00:02:10 10
101 A 01/12/2017 00:02:40 25
101 A 01/12/2017 00:03:20 18
101 B 01/12/2017 00:03:55 30
101 B 01/12/2017 00:04:05 10
101 B 01/12/2017 00:04:30 20
101 B 01/12/2017 00:04:50 10
101 A 01/12/2017 00:05:00 28
101 A 01/12/2017 00:05:50 18
101 A 01/12/2017 00:06:20 18
102 A 01/12/2017 00:02:10 10
102 A 01/12/2017 00:02:40 25
102 A 01/12/2017 00:03:20 18
102 B 01/12/2017 00:03:55 30
102 B 01/12/2017 00:04:05 10
102 B 01/12/2017 00:04:30 20
102 B 01/12/2017 00:04:50 10
102 A 01/12/2017 00:05:00 28
102 A 01/12/2017 00:05:50 18
102 A 01/12/2017 00:06:20 18
从这个表中,我需要在下面提到输出
===========================================
UnitID StatusA StatusB MaxValue
===========================================
101 02:30 00:55 30
102 02:30 00:55 30
我需要的是状态的总时差。那么如何在mssql查询中实现这一点呢。这里02:30是表中状态“A”的持续时间
高级谢谢。据我所知,您不能在不同的列中显示状态,只能按行显示
SELECT [UnitID], [Status], MAX([DateTime]) - MIN([DateTime]), MAX([Value])
FROM [theTable]
GROUP BY [UnitID], [Status]
输出将是
101 A 02:30 30
101 B 00:55 30
102 A 02:30 30
102 B 00:55 30
如果你有固定的A和B状态,你可以把事情搞得一团糟,这样做:
SELECT UnitID, A, B, MaxValue
FROM
(
SELECT [UnitID], MAX([DateTime]) - MIN([DateTime]) AS A, null AS B, MAX([Value]) AS MaxValue
FROM [theTable]
WHERE Status = 'A'
GROUP BY [UnitID]
UNION ALL
SELECT [UnitID], null, MAX([DateTime]) - MIN([DateTime]), MAX([Value])
FROM [theTable]
WHERE Status = 'B'
GROUP BY [UnitID]
) x
您可以获得每个组的差异:
select unitid, status, min(datetime) as mindt, max(datetime) as maxdt, max(value) as maxvalue
from (select t.*,
row_number() over (partition by unitid order by datetime) as seqnum,
row_number() over (partition by unitid, status order by datetime) as seqnum_s
from t
) t
group by unitid, status, (seqnum - seqnum_s);
这就解决了“群体和岛屿”问题。现在,您可以使用条件聚合获得所需的信息:
with t as (
select unitid, status, min(datetime) as mindt, max(datetime) as maxdt, max(value) as maxvalue
from (select t.*,
row_number() over (partition by unitid order by datetime) as seqnum,
row_number() over (partition by unitid, status order by datetime) as seqnum_s
from t
) t
group by unitid, status, (seqnum - seqnum_s)
)
select unitid,
sum(case when status = 'A' then datediff(minute, mindt, maxdt) end) as a_minutes,
sum(case when status = 'b' then datediff(minute, mindt, maxdt) end) as a_minutes,
max(maxvalue)
from t
group by unitid;
我将让您自行将分钟转换回时间。您可以通过以下查询执行所需操作。我试着在不同的CTE上分开每一步,这样你就可以一步一步地看到如何得到你的结果
LAG
将检索上一行值(按分区按
列拆分,按顺序按
排序)
他不是在做最大-最小,他是在做和以前的记录不同的时间和状态。通过使用pivot,您可以在不同的列中拥有不同的状态。@EzLo以前不知道“pivot”,但看起来不错。刚学到一些新东西。谢谢是@Ezlo我想计算日期与以前记录之间的差异。但我也有固定的身份号码。使用pivot,我们可以按状态准备列,但我不知道如何计算记录之间的差异。谢谢@Gordon Linoff您的解决方案也适用于我。但埃兹洛详细描述了它,所以我认为这是一个正确的答案。@ronak。在我看来,这是一个更复杂的问题。
;WITH LaggedValues AS
(
SELECT
M.UnitID,
M.Status,
M.DateTime,
LaggedDateTime = LAG(M.DateTime) OVER (PARTITION BY M.UnitID ORDER BY M.DateTime ASC),
LaggedStatus = LAG(M.Status) OVER (PARTITION BY M.UnitID ORDER BY M.DateTime ASC)
FROM
Measures AS M
),
TimeDifferences AS
(
SELECT
T.*,
SecondDifference = CASE
WHEN T.Status = T.LaggedStatus THEN DATEDIFF(SECOND, T.LaggedDateTime, T.DateTime) END
FROM
LaggedValues AS T
),
TotalsByUnitAndStatus AS
(
SELECT
T.UnitID,
T.Status,
SecondDifference = SUM(T.SecondDifference)
FROM
TimeDifferences AS T
GROUP BY
T.UnitID,
T.Status
),
TotalsByUnit AS -- Conditional aggregation (alternative to PIVOT)
(
SELECT
T.UnitID,
StatusA = MAX(CASE WHEN T.Status = 'A' THEN T.SecondDifference END),
StatusB = MAX(CASE WHEN T.Status = 'B' THEN T.SecondDifference END)
FROM
TotalsByUnitAndStatus AS T
GROUP BY
T.UnitID
)
SELECT
T.UnitID,
StatusA = CONVERT(VARCHAR(10), T.StatusA / 60) + ':' + CONVERT(VARCHAR(10), T.StatusA % 60),
StatusB = CONVERT(VARCHAR(10), T.StatusB / 60) + ':' + CONVERT(VARCHAR(10), T.StatusB % 60)
FROM
TotalsByUnit AS T