选择满足特定条件的行和旁边的行

时间:2018-04-09 15:16:32

标签: sql-server lag rank row-number lead

假设我有一个历史表来保存谁修改了数据

-------------------------------------------------------------
|      ID      |  Last_Modif                  | User_Modif   | Col3, Col4...
-------------------------------------------------------------
|       1      |     2018-04-09 12:12:00      | John
|       2      |     2018-04-09 11:10:00      | Jim
|       3      |     2018-04-09 11:05:00      | Mary
|       4      |     2018-04-09 11:00:00      | John
|       5      |     2018-04-09 10:56:00      | David
|       6      |     2018-04-09 10:53:00      | John
|       7      |     2018-04-08 19:50:00      | Eric
|       8      |     2018-04-08 18:50:00      | Chris
|       9      |     2018-04-08 15:50:00      | John
|       10     |     2018-04-08 12:50:00      | Chris
----------------------------------------------------------

我想在他做之前找到John和之前版本所做的修改,以检查他修改了什么。例如,在这种情况下,我想返回第1,2,4,5,6,7,9,10行

我正在考虑基于Last_modif排名第一,然后进行连接以获取下一行,但不知何故结果不正确。这似乎不是LAG / LEAD案例,因为我没有从下一行中选择单个值,而是整个下一行。有什么想法吗?

-- sample 1000 rows with RowNumber
with TopRows as
  (select top 1000 *, ROW_NUMBER() OVER(ORDER BY Last_modif desc) RowNum from [Table])
--Reference rows : Rows modif by John
  , ModifByJohn as
  (Select * from TopRows where USER_MODIF = 'John')

  select * from ModifByJohn
  UNION
  select ModifByNext.* from ModifByJohn join TopRows ModifbyNext on ModifByJohn.RowNum + 1 = ModifByNext.RowNum
  order by RowNum

如果我们想在John之前返回最后2个修改而不是1,那么代码将如何显示?

1 个答案:

答案 0 :(得分:0)

也许您可以利用您当前的ID:

with x as
(
    select t1.*,
           (select top 1 id from tbl where id > t1.id) prev_id
    from  tbl t1
    where t1.User_Modif = 'John'
)
select * from x;
GO
ID | Last_Modif          | User_Modif | prev_id
-: | :------------------ | :--------- | ------:
 1 | 09/04/2018 12:12:00 | John       |       2
 4 | 09/04/2018 11:00:00 | John       |       5
 6 | 09/04/2018 10:53:00 | John       |       7
 9 | 08/04/2018 15:50:00 | John       |      10
with x as
(
    select t1.*,
           (select top 1 id from tbl where id > t1.id) prev_id
    from  tbl t1
    where t1.User_Modif = 'John'
)
select ID, Last_Modif, User_Modif from x
union all 
select ID, Last_Modif, User_Modif 
from tbl
where  ID in (select prev_id from x)
order by ID
GO
ID | Last_Modif          | User_Modif
-: | :------------------ | :---------
 1 | 09/04/2018 12:12:00 | John      
 2 | 09/04/2018 11:10:00 | Jim       
 4 | 09/04/2018 11:00:00 | John      
 5 | 09/04/2018 10:56:00 | David     
 6 | 09/04/2018 10:53:00 | John      
 7 | 08/04/2018 19:50:00 | Eric      
 9 | 08/04/2018 15:50:00 | John      
10 | 08/04/2018 12:50:00 | Chris     

dbfiddle here