排名还是依靠新值?

时间:2019-04-30 08:26:55

标签: sql sql-server sql-server-2008 rank

我有下表(其他几个表中的临时表)

PersonID    Date                        Status
1337        2019-04-24 02:28:53.677     DR 
1337        2019-04-24 05:23:17.410     XM 
1337        2019-04-24 06:51:00.160     DR 
1337        2019-04-24 12:58:02.783     DR 
1337        2019-04-24 13:23:26.150     UPD
1337        2019-04-24 13:24:54.527     UPD
1337        2019-04-24 13:42:36.503     UPD
1337        2019-04-24 13:42:36.970     D
1337        2019-04-24 13:45:19.020     D
1337        2019-04-24 13:45:20.800     A
1337        2019-04-24 13:48:56.393     A
1337        2019-04-24 13:48:57.143     UPD
1337        2019-04-24 13:49:57.630     UPD
1337        2019-04-24 13:50:37.613     A

试图获得以下排名,因为我有兴趣将其分组分组

PersonID    Date                        Status   Rank
1337        2019-04-24 02:28:53.677     DR       1
1337        2019-04-24 05:23:17.410     XM       2
1337        2019-04-24 06:51:00.160     DR       3
1337        2019-04-24 12:58:02.783     DR       3
1337        2019-04-24 13:23:26.150     UPD      4
1337        2019-04-24 13:24:54.527     UPD      4
1337        2019-04-24 13:42:36.503     UPD      4
1337        2019-04-24 13:42:36.970     D        5
1337        2019-04-24 13:45:19.020     D        5
1337        2019-04-24 13:45:20.800     A        6
1337        2019-04-24 13:48:56.393     A        6
1337        2019-04-24 13:48:57.143     UPD      7
1337        2019-04-24 13:49:57.630     UPD      7
1337        2019-04-24 13:50:37.613     A        8

尝试使用

Select Time, Status, 
  RANK() OVER (partition by ResourceStatusCode order by ReportedDateTime ) as R1
 ,ROW_NUMBER() OVER(partition by ResourceStatusCode ORDER BY ReportedDateTime) as RN2
from #tbl1
order by Time

我应该尝试在每种新状态下使用另一种带有行号的方法吗?

我们的服务器(SQL Server 2008)已禁用Lead()和lag()函数,求和超过

2 个答案:

答案 0 :(得分:1)

这里是一种更为简洁的方法,应该将您需要的内容交付给您:

declare @t table(PersonID int,DateValue datetime,Stat varchar(5));
insert into @t values (1337,'2019-04-24 02:28:53.677','DR'),(1337,'2019-04-24 05:23:17.410','XM'),(1337,'2019-04-24 06:51:00.160','DR'),(1337,'2019-04-24 12:58:02.783','DR'),(1337,'2019-04-24 13:23:26.150','UPD'),(1337,'2019-04-24 13:24:54.527','UPD'),(1337,'2019-04-24 13:42:36.503','UPD'),(1337,'2019-04-24 13:42:36.970','D'),(1337,'2019-04-24 13:45:19.020','D'),(1337,'2019-04-24 13:45:20.800','A'),(1337,'2019-04-24 13:48:56.393','A'),(1337,'2019-04-24 13:48:57.143','UPD'),(1337,'2019-04-24 13:49:57.630','UPD'),(1337,'2019-04-24 13:50:37.613','A');

with d as
(
    select PersonID
          ,DateValue
          ,Stat
          ,row_number() over (order by DateValue,Stat) as rn
    from @t
)
select d1.PersonID
      ,d1.DateValue
      ,d1.Stat
      ,sum(case when d1.Stat = d2.Stat then 0 else 1 end) over (order by d1.DateValue) as Ranking
from d as d1
    left join d as d2
        on d1.rn-1 = d2.rn
order by d1.DateValue

输出

+----------+-------------------------+------+---------+
| PersonID |        DateValue        | Stat | Ranking |
+----------+-------------------------+------+---------+
|     1337 | 2019-04-24 02:28:53.677 | DR   |       1 |
|     1337 | 2019-04-24 05:23:17.410 | XM   |       2 |
|     1337 | 2019-04-24 06:51:00.160 | DR   |       3 |
|     1337 | 2019-04-24 12:58:02.783 | DR   |       3 |
|     1337 | 2019-04-24 13:23:26.150 | UPD  |       4 |
|     1337 | 2019-04-24 13:24:54.527 | UPD  |       4 |
|     1337 | 2019-04-24 13:42:36.503 | UPD  |       4 |
|     1337 | 2019-04-24 13:42:36.970 | D    |       5 |
|     1337 | 2019-04-24 13:45:19.020 | D    |       5 |
|     1337 | 2019-04-24 13:45:20.800 | A    |       6 |
|     1337 | 2019-04-24 13:48:56.393 | A    |       6 |
|     1337 | 2019-04-24 13:48:57.143 | UPD  |       7 |
|     1337 | 2019-04-24 13:49:57.630 | UPD  |       7 |
|     1337 | 2019-04-24 13:50:37.613 | A    |       8 |
+----------+-------------------------+------+---------+

编辑以下版本信息

由于您使用的是v2008,因此窗口聚合中没有order by,因此您的选择受到限制。我真正看到的无需升级即可实现的唯一方法是使用递归cte:

declare @t table(PersonID int,DateValue datetime,Stat varchar(5));
insert into @t values (1337,'2019-04-24 02:28:53.677','DR'),(1337,'2019-04-24 05:23:17.410','XM'),(1337,'2019-04-24 06:51:00.160','DR'),(1337,'2019-04-24 12:58:02.783','DR'),(1337,'2019-04-24 13:23:26.150','UPD'),(1337,'2019-04-24 13:24:54.527','UPD'),(1337,'2019-04-24 13:42:36.503','UPD'),(1337,'2019-04-24 13:42:36.970','D'),(1337,'2019-04-24 13:45:19.020','D'),(1337,'2019-04-24 13:45:20.800','A'),(1337,'2019-04-24 13:48:56.393','A'),(1337,'2019-04-24 13:48:57.143','UPD'),(1337,'2019-04-24 13:49:57.630','UPD'),(1337,'2019-04-24 13:50:37.613','A');

with d as
(
    select PersonID
          ,DateValue
          ,Stat
          ,row_number() over (order by DateValue,Stat) as rn
    from @t
)
,r as
(
    select PersonID
          ,DateValue
          ,Stat
          ,rn
          ,cast(1 as int) as Ranking
    from d
    where rn = 1

    union all

    select d.PersonID
          ,d.DateValue
          ,d.Stat
          ,d.rn
          ,case when d.Stat = r.Stat then r.Ranking else r.Ranking+1 end as Ranking
    from r
        join d
            on r.rn+1 = d.rn
)
select PersonID
      ,DateValue
      ,Stat
      ,Ranking
from r
order by DateValue;

答案 1 :(得分:0)

尝试以下操作:

WITH cte AS(
  SELECT PersonID,CAST([Date] AS datetime) [Date],[Status]
  FROM
    (VALUES
      (1337,'2019-04-24 02:28:53.677','DR '),
      (1337,'2019-04-24 05:23:17.410','XM '),
      (1337,'2019-04-24 06:51:00.160','DR '),
      (1337,'2019-04-24 12:58:02.783','DR '),
      (1337,'2019-04-24 13:23:26.150','UPD'),
      (1337,'2019-04-24 13:24:54.527','UPD'),
      (1337,'2019-04-24 13:42:36.503','UPD'),
      (1337,'2019-04-24 13:42:36.970','D  '),
      (1337,'2019-04-24 13:45:19.020','D  '),
      (1337,'2019-04-24 13:45:20.800','A  '),
      (1337,'2019-04-24 13:48:56.393','A  '),
      (1337,'2019-04-24 13:48:57.143','UPD'),
      (1337,'2019-04-24 13:49:57.630','UPD'),
      (1337,'2019-04-24 13:50:37.613','A  ')
    ) v(PersonID,[Date],[Status])
)
SELECT
  PersonID,
  [Date],
  [Status],
  SUM(IsNext)OVER(PARTITION BY PersonID ORDER BY [Date],[Status])+1 [Rank]
FROM
  (
    SELECT *,IIF(LAG([Status])OVER(PARTITION BY PersonID ORDER BY [Date],[Status])<>[Status],1,0) IsNext
    FROM cte
  ) q
ORDER BY PersonID,[Date],[Status]

没有LAG的变体:

WITH cte1 AS(
  SELECT PersonID,CAST([Date] AS datetime) [Date],[Status]
  FROM
    (VALUES
      (1337,'2019-04-24 02:28:53.677','DR '),
      (1337,'2019-04-24 05:23:17.410','XM '),
      (1337,'2019-04-24 06:51:00.160','DR '),
      (1337,'2019-04-24 12:58:02.783','DR '),
      (1337,'2019-04-24 13:23:26.150','UPD'),
      (1337,'2019-04-24 13:24:54.527','UPD'),
      (1337,'2019-04-24 13:42:36.503','UPD'),
      (1337,'2019-04-24 13:42:36.970','D  '),
      (1337,'2019-04-24 13:45:19.020','D  '),
      (1337,'2019-04-24 13:45:20.800','A  '),
      (1337,'2019-04-24 13:48:56.393','A  '),
      (1337,'2019-04-24 13:48:57.143','UPD'),
      (1337,'2019-04-24 13:49:57.630','UPD'),
      (1337,'2019-04-24 13:50:37.613','A  ')
    ) v(PersonID,[Date],[Status])
),
cte2 AS(
  SELECT *,ROW_NUMBER()OVER(PARTITION BY PersonID ORDER BY [Date],[Status]) N
  FROM cte1
)
SELECT
  PersonID,
  [Date],
  [Status],
  SUM(IsNext)OVER(PARTITION BY PersonID ORDER BY [Date],[Status])+1 [Rank]
FROM
  (
    SELECT q1.*,CASE WHEN q1.[Status]<>q2.[Status] THEN 1 ELSE 0 END IsNext
    FROM cte2 q1
    LEFT JOIN cte2 q2 ON q1.PersonID=q2.PersonID AND q1.N=q2.N+1
  ) q
ORDER BY PersonID,[Date],[Status]