在同一列中排名并查找值的差异

Rank & find difference of value in the same column

我有以下 table -

在这里,我创建了 "Order" 列,方法是使用按 case_identifier 分区并按 audit_date 排序的排名函数。

现在,我想创建一个新列如下 -

新列的逻辑是 -

select *,
case when [order] = '1' then [days_diff]
     else (val of [days_diff] in rank 2) - (val of [days_diff] in rank 1) ...
end as '[New_Col]'
from TABLE

你能帮我看看语法吗?谢谢

我相信以下查询可以满足您的需求。

SELECT a.*,
 'NEW DAYS DIFF' =
CASE 
    WHEN  a.[order] = 1 THEN a.days_diff 
    ELSE a.days_diff - b.days_diff  
END 
FROM dbo.tblCaseDaysDiff a
INNER JOIN dbo.tblCaseDaysDiff b
ON
 (b.CASE_ID = a.CASE_ID AND b.[order] + 1 = a.[order] )  -- Get the current row and compare with the next highest order
OR (b.CASE_ID = a.CASE_ID AND b.[order] = 1 AND a.[order] = 1) --WHEN ORDER = 1 Get days_diff value
ORDER BY a.CASE_ID, a.[order]

看看 LAG 函数。它会为你提供你想要的。

类似于:

declare @temptable TABLE (case_id varchar(2), row_order int, days_diff float)
INSERT INTO @temptable values ('A',1,5)
INSERT INTO @temptable values ('A',2,3)
INSERT INTO @temptable values ('A',3,2)
INSERT INTO @temptable values ('B',1,5)
INSERT INTO @temptable values ('B',2,1)

--select * from @temptable

SELECT case_id,row_order, LAG(days_diff,1) OVER (PARTITION BY case_id ORDER BY row_order) AS prev_row,days_diff,
CASE 
WHEN row_order = 1 THEN days_diff
ELSE LAG(days_diff,1) OVER (PARTITION BY case_id ORDER BY row_order) - days_diff
END AS newcolumn
FROM @temptable
order by case_id,row_order asc


SELECT case_id,row_order,LAG(days_diff,1) OVER (PARTITION BY case_id ORDER BY row_order) AS prev_row, days_diff,
COALESCE(LAG(days_diff,1) OVER (PARTITION BY case_id ORDER BY row_order) - days_diff , days_diff)
FROM @temptable
order by case_id,row_order asc

其他答案将使用合并来代替 CASE 语句。可能会更快,但我觉得这样更清晰。

如果您 运行 两者并查看执行计划,它们是相同的。

碰巧,您已经精通 window 函数,正如其他人指出的那样,LAG 可以解决问题。不过,一般来说,您总是可以通过生成一行来获得两行的差异:通过将 table 连接到自身。

with T (CASE_IDENTIFIER, AUDIT_DATE, order, days_diff)
as (
   ... your query ...
)
select a.*,
       a.days_diff - coalesce(b.days_diff, 0) as delta_days_diff
from T as a left join T as b
on a.CASE_IDENTIFIER = b.CASE_IDENTIFIER
and b.days_diff = a.days_diff - 1

滞后法

SELECT
    CASE_IDENTIFIER
    ,AUDIT_DATE
    ,[order]
    ,days_diff
    ,days_diff - ISNULL(LAG(days_diff,1) OVER (PARTITION BY CASE_IDENTIFIER ORDER BY [order]),0) AS New_Column
FROM @Table

自连接方法

SELECT
    t1.CASE_IDENTIFIER
    ,AUDIT_DATE
    ,t1.[order]
    ,t1.days_diff
    ,t1.days_diff - ISNULL(t2.days_diff,0) AS New_Column
FROM
    @Table t1
    LEFT JOIN @Table t2
    ON t1.CASE_IDENTIFIER = t2.CASE_IDENTIFIER
    AND t1.[order] - 1 = t2.[order]

我觉得很多其他答案都在正确的轨道上,但有一些细微差别或更简单的编写方式。或者还有一些答案提供了写入方向,但它们的连接或语法有问题。无论如何,无论您使用 SELF JOIN 方法的 LAG,您都不需要 CASE STATEMENT。 Next COALESCE() 很棒,但您只比较了 2 个值,因此 ISNULL() 对于 sql-server 也可以正常工作,但两者都可以。