在同一列中排名并查找值的差异
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 也可以正常工作,但两者都可以。
我有以下 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 也可以正常工作,但两者都可以。