MS 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

我有下面的sql表

======================================================
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