我有下表,它代表了票务数据库的操作细节。我想要做的是在每个票证上水平显示最后10个不同的操作,每个状态与前一个状态之间的日期差异(以天为单位)。
这是原始表:
Case_number Operation_Name Date
112345 Canceled 22.04.2018
112345 On hold 20.04.2018
112345 On hold 15.04.2018
112345 Processing 10.04.2018
112345 Open 08.04.2018
112347 Closed 21.04.2018
112347 On hold 20.04.2018
112347 On hold 18.04.2018
112347 Processing 15.04.2018
112347 Processing 13.04.2018
112347 Open 11.04.2018
输出应该如下所示
如你所见:
112347 On hold 20.04.2018
112347 On hold 18.04.2018
可能存在重复状态,我必须仅提取第一个日期(18.04.2018)。
我尝试使用主导功能,但我没有运气。
提前感谢您的时间和想法!
答案 0 :(得分:1)
可以将此作为一个直接的SQL查询,但需要一些肘部油脂。
基本上,我们需要 1.为每个case_number和。建立行顺序 2.执行双透视操作以逐步将Operation_Name列和Days_Elapsed列分别放入每列中
请参阅下文,了解最多可处理4个步骤的解决方案。如果需要,可以通过修改此步骤来添加更多步骤,这很简单。使用CTE和中间结果来了解制定此步骤的步骤。
MS SQL Server 2017架构设置:
create table test (id int, status varchar(max), date datetime)
insert test values
(1, 'cancelled', '2018-04-07'),
(1, 'hold', '2018-04-05'),
(1, 'processing', '2018-04-04'),
(1, 'processing', '2018-04-02'),
(2, 'processing', '2018-04-01'),
(2, 'cancelled', '2018-04-07')
查询1 :
;WITH Ordered AS (
SELECT id, status, date,
ROW_NUMBER() OVER(PARTITION BY id ORDER BY date desc) AS rowNumber,
LEAD(date) OVER(PARTITION BY id ORDER BY date desc) AS prevDate
FROM test
)
SELECT
id,
MAX([1]) AS Operation_Latest,
MAX([D1]) AS DaysElapsed_Prev1_Latest,
MAX([2]) AS Operation_Prev1,
MAX([D2]) AS DaysElapsed_Prev2_Prev1,
MAX([3]) AS Operation_Prev2,
MAX([D3]) AS DaysElapsed_Prev3_Prev2,
MAX([4]) AS Operation_Prev3,
MAX([D4]) AS DaysElapsed_Prev4_Prev3
FROM
(SELECT id, rowNumber, status,
DATEDIFF(day, prevDate, date) AS daysSinceLast,
'D' + CONVERT(varchar, rowNumber) AS DaysPivot
FROM Ordered) AS p
PIVOT
(
MAX(status) FOR rowNumber IN ([1], [2], [3], [4])
) AS pv1
PIVOT
(
MAX(daysSinceLast) FOR daysPivot IN ([D1], [D2], [D3], [D4])
) AS pv2
GROUP BY id
<强> Results 强>:
| id | Operation_Latest | DaysElapsed_Prev1_Latest | Operation_Prev1 | DaysElapsed_Prev2_Prev1 | Operation_Prev2 | DaysElapsed_Prev3_Prev2 | Operation_Prev3 | DaysElapsed_Prev4_Prev3 |
|----|------------------|--------------------------|-----------------|-------------------------|-----------------|-------------------------|-----------------|-------------------------|
| 1 | cancelled | 2 | hold | 1 | processing | 2 | processing | (null) |
| 2 | cancelled | 6 | processing | (null) | (null) | (null) | (null) | (null) |
答案 1 :(得分:1)
这将删除具有相同状态的其他行并分配序列号:
with cte as
(
select *,
lead(Operation_Name) -- previous Operation_Name
over (partition by case_number
order by Dat desc) as prev_op
from tab
)
select cte.*,
datediff(day
,date
,lag(date) -- next date
over (partition by case_number
order by Date desc)
) as days_between,
row_number()
over (partition by case_number
order by Date desc) as rn
from cte
where prev_op <> Operation_Name -- different value
or prev_op is null -- or first row
;
现在您可以将此传递给PIVOT或执行old-syle max(case):
with cte as
(
select *,
lead(Operation_Name) -- previous Operation_Name
over (partition by case_number
order by Date desc) as prev_op
from tab
)
, cte2 as
(
select cte.*,
datediff(day
,date
,lag(date) -- previous Operation_Name
over (partition by case_number
order by Date desc)
) as days_between,
row_number()
over (partition by case_number
order by Date desc) as rn
from cte
where prev_op <> Operation_Name -- different value
or prev_op is null -- or first row
)
select case_number,
max(case when rn = 1 then Operation_Name end),
max(case when rn = 2 then Operation_Name end),
max(case when rn = 2 then days_between end),
max(case when rn = 3 then Operation_Name end),
max(case when rn = 3 then days_between end),
max(case when rn = 4 then Operation_Name end),
max(case when rn = 4 then days_between end)
from cte2
group by case_number