SQL通过匹配值执行日差

SQL performing day difference by matching value

我的目标是获取1st OLD1st NEW状态达到1st END时的持续时间。

例如:Table1

ID   Day STATUS
111   1   NEW
111   2   NEW
111   3   OLD
111   4   END
111   5   END
112   1   OLD
112   2   OLD
112   3   NEW
112   4   NEW
112   5   END
113   1   NEW
113   2   NEW

期望的结果是:

STATUS Count

NEW 2 (1 for ID 111-New on day 1 to End on day 4,and 1 for 112-new on day 3 to End on day 5)

OLD 2 (1 for ID 111-Old on day 3 to End on day 4, and 1 for 112-OLD on day 1 to End on day 5)

以下是 T-SQL(SQL 服务器)并且在 MySQL 中不可用。 dbms 的选择在一个问题中至关重要,因为有太多 dbms 特定的选择要做。下面的查询需要使用 "window function" row_number() over()common table expression 两者都不存在于 MySQL 中(但总有一天会存在)。该解决方案还使用 cross apply,它(迄今为止)是 SQL 服务器特定的,但在 Postgres 和 Oracle 12 中有使用 lateral joins.

的替代方案

SQL Fiddle

MS SQL Server 2014 架构设置:

CREATE TABLE Table1
    (id int, day int, status varchar(3))
;

INSERT INTO Table1
    (id, day, status)
VALUES
    (111, 1, 'NEW'),
    (111, 2, 'NEW'),
    (111, 3, 'OLD'),
    (111, 4, 'END'),
    (111, 5, 'END'),
    (112, 1, 'OLD'),
    (112, 2, 'OLD'),
    (112, 3, 'NEW'),
    (112, 4, 'NEW'),
    (112, 5, 'END'),
    (113, 1, 'NEW'),
    (113, 2, 'NEW')
;

查询 1:

with cte as (
      select
              *
      from (
        select t.*
              , row_number() over(partition by id, status order by day) rn
        from table1 t
            ) d
      where rn = 1
      )
select 
       t.id, t.day, ca.nxtDay, t.Status, ca.nxtStatus   
from cte t
outer apply (
    select top(1) Status, day
    from cte nxt
    where t.id = nxt.id
    and t.status = 'NEW' and nxt.status = 'END'
    order by day
    ) ca (nxtStatus, nxtDay)
where nxtStatus IS NOT NULL or Status = 'OLD'
order by id, day

Results:

|  id | day | nxtDay | Status | nxtStatus |
|-----|-----|--------|--------|-----------|
| 111 |   1 |      4 |    NEW |       END |
| 111 |   3 | (null) |    OLD |    (null) |
| 112 |   1 | (null) |    OLD |    (null) |
| 112 |   3 |      5 |    NEW |       END |

如您所见,计算 Status 列将导致 NEW = 2 和 OLD = 2