我试图弄清楚如何创建一个由多列分区的序列,其中序列必须在另一个(基于日期的)列不连续时重置。
问题:医院ADT(入院/出院/转院)事件发生在特定时间点,但我们希望将这些事件转变为具有持续时间(时间跨度)的活动,即我们有开始日期,但不要# 39; t具有结束日期,该日期基于下一个适当的ADT事件。我们已在代码中完成此操作,但也希望在SQL中执行此操作以提高性能。例如找到在ICU中度过超过48小时的患者。
我们希望记录六个不同级别的站点位置:设施,护理点,建筑物,楼层,房间和床。
示例:
Stream Event Started Facility PointOfCare ...
1 1 2015-01-01 09:05 Hospital-A ICU
1 2 2015-01-02 13:10 Hospital-A WARD-1
2 3 2015-02-10 12:00 Hospital-A ICU
2 4 2015-02-11 12:00 Hospital-A ICU
2 5 2015-02-12 04:30 Hospital-A WARD-2
因此,对于每个事件,我们想知道它们在每个特定站点位置的时间长度。每个流中最后一个活动的结束日期为空(仍为住院病人)或病人出院的日期。
这是我目前的解决方案:
-- Create a sequence for each site location
INSERT INTO ADT_Activity_Sequence
SELECT
[Stream],
[Event],
[Started],
[Facility],
ROW_NUMBER() OVER (PARTITION BY [Stream],
ISNULL([Facility], [Event])
ORDER BY [Started]) AS [FacilitySequence],
[PointOfCare],
ROW_NUMBER() OVER (PARTITION BY [Stream],
ISNULL([Facility], [Event]),
ISNULL([PointOfCare], [Event])
ORDER BY [Started]) AS [PointOfCareSequence]
-- and so on for all site locations
FROM ADT_Event
INNER JOIN ADT_Stream ON ADT_Event.Stream = Stream.Id
示例:
Stream Event Started Facility FacilitySequence PointOfCare PointOfCareSequence ...
1 1 2015-01-01 09:05 Hospital-A 1 ICU 1
1 2 2015-01-02 13:10 Hospital-A 2 WARD-1 1
2 3 2015-02-10 12:00 Hospital-A 1 ICU 1
2 4 2015-02-11 12:00 Hospital-A 2 ICU 2
2 5 2015-02-12 04:30 Hospital-A 3 WARD-2 1
然后从序列创建持续时间:
INSERT INTO ADT_Activity_Duration
SELECT
[Stream],
[Event],
[Started],
[Facility],
[Sequence].[FacilitySequence],
(
-- Find most recent activity which is the first in current sequence
SELECT TOP 1 [FacilitySequence].[Started]
FROM [ADT_Activity_Sequence] [FacilitySequence]
WHERE [FacilitySequence].[Stream] = [Event].[Stream] AND [FacilitySequence].[FacilitySequence] = 1 AND [FacilitySequence].[Started] <= [Event].[Started]
ORDER BY [FacilitySequence].[Started] DESC
) AS [FacilityStarted],
(
-- Find first activity in next sequence as this activities end date
-- Last activity returns null, so activity uses stream end date if set
ISNULL((
SELECT TOP 1 [FacilitySequence].[Started]
FROM [ADT_Activity_Sequence] [FacilitySequence]
WHERE [FacilitySequence].[Stream] = [Event].[Stream] AND [FacilitySequence].[FacilitySequence] = 1 AND [FacilitySequence].[Started] > [Event].[Started]
ORDER BY [FacilitySequence].[Started]), [Stream].[Ended])
) AS [FacilityEnded],
[PointOfCare],
[Sequence].[PointOfCareSequence],
(
SELECT TOP 1 [PointOfCareSequence].[Started]
FROM [ADT_Activity_Sequence] [PointOfCareSequence]
WHERE [PointOfCareSequence].[Stream] = [Event].[Stream] AND [PointOfCareSequence].[PointOfCareSequence] = 1 AND [PointOfCareSequence].[Started] <= [Event].[Started]
ORDER BY [PointOfCareSequence].[Started] DESC
) AS [PointOfCareStarted],
(
ISNULL((
SELECT TOP 1 [PointOfCareSequence].[Started]
FROM [ADT_Activity_Sequence] [PointOfCareSequence]
WHERE [PointOfCareSequence].[Stream] = [Event].[Stream] AND [PointOfCareSequence].[PointOfCareSequence] = 1 AND [PointOfCareSequence].[Started] > [Event].[Started]
ORDER BY [PointOfCareSequence].[Started]), [Stream].[Ended])
) AS [PointOfCareEnded]
-- and so on for all site locations
FROM ADT_Event AS [Event]
INNER JOIN [ADT_Stream] AS [Stream] ON [Event].[Stream] = [Stream].[Id]
INNER JOIN [ADT_Activity_Sequence] [Sequence] ON [Event].[Id] = [Sequence].[Event]
示例:
Stream Event Started Facility FacilitySequence FacilityStarted FacilityEnded PointOfCare PointOfCareSequence PointOfCareStarted PointOfCareEnded ...
1 1 2015-01-01 09:05 Hospital-A 1 2015-01-01 09:05 2015-01-03 12:00 ICU 1 2015-01-01 09:05 2015-01-02 13:10
1 2 2015-01-02 13:10 Hospital-A 2 2015-01-01 09:05 2015-01-03 12:00 WARD-1 1 2015-01-02 13:10 2015-01-03 12:00
2 3 2015-02-10 12:00 Hospital-A 1 2015-02-10 12:00 <NULL> ICU 1 2015-02-10 12:00 2015-02-12 04:30
2 4 2015-02-11 12:00 Hospital-A 2 2015-02-10 12:00 <NULL> ICU 2 2015-02-10 12:00 2015-02-12 04:30
2 5 2015-02-12 04:30 Hospital-A 3 2015-02-10 12:00 <NULL> WARD-2 1 2015-02-12 04:30 <NULL>
我的问题是当连续的日期序列被破坏时,当患者从任何站点位置转移,然后再次转回时,所有这些都发生在同一个流中:
Stream Event Started Facility PointOfCare ...
3 1 2015-03-01 09:05 Hospital-A ICU
3 2 2015-03-02 13:10 Hospital-A WARD-1
3 3 2015-03-02 10:00 Hospital-A ICU
示例:
Stream Event Started Facility FacilitySequence PointOfCare PointOfCareSequence ...
3 1 2015-03-01 09:05 Hospital-A 1 ICU 1
3 2 2015-03-02 13:10 Hospital-A 2 WARD-1 1
3 3 2015-03-02 10:00 Hospital-A 3 ICU 2
注意事件#3的护理点序列为2,这是不正确的,由于事件#2位于不同的位置,需要将其重置为1.
我已经在圈子里走了一段时间了:)所以任何帮助表示赞赏,谢谢!
答案 0 :(得分:5)
如果我理解你的问题,你需要连续ROW_NUMBER()
。您可以使用流ROW_NUMBER()
和单个序列之间的行数差异来生成一个组,在该组上可以为设施和护理点订购行号。
由于这些不是使用Facility
和PointofCare
直接分组,而是基于它们的顺序,如果患者再次切换回相同的设施或护理点,则重置序列。
使用类似的东西。 SQL Fiddle
;WITH CTE as
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY Stream ORDER BY [Started]) as StreamSequence,
ROW_NUMBER() OVER(PARTITION BY Stream ORDER BY [Started]) - ROW_NUMBER() OVER(PARTITION BY Facility ORDER BY [Started]) as FacilityGroup,
ROW_NUMBER() OVER(PARTITION BY Stream ORDER BY [Started]) - ROW_NUMBER() OVER(PARTITION BY PointOfCare ORDER BY [Started]) as PointOfCareGroup
FROM Stream
)
SELECT
Stream, Event, Started, Facility, PointOfCare, StreamSequence,
ROW_NUMBER() OVER(PARTITION BY Stream,FacilityGroup ORDER BY [Started]) as FacilitySequence,
ROW_NUMBER() OVER(PARTITION BY Stream,PointOfCareGroup ORDER BY [Started]) as PointOfCareSequence
FROM CTE
ORDER BY Event;
您可以根据需要根据这些顺序生成日期范围。
<强>输出强>
| Stream | Event | Started | Facility | PointOfCare | StreamSequence | FacilitySequence | PointOfCareSequence |
|--------|-------|----------------------------|------------|-------------|----------------|------------------|---------------------|
| 1 | 1 | January, 01 2015 09:05:00 | Hospital-A | ICU | 1 | 1 | 1 |
| 1 | 2 | January, 02 2015 13:10:00 | Hospital-A | WARD-1 | 2 | 2 | 1 |
| 2 | 3 | February, 10 2015 12:00:00 | Hospital-A | ICU | 1 | 1 | 1 |
| 2 | 4 | February, 11 2015 12:00:00 | Hospital-A | ICU | 2 | 2 | 2 |
| 2 | 5 | February, 12 2015 04:30:00 | Hospital-A | WARD-2 | 3 | 3 | 1 |
| 2 | 6 | February, 12 2015 05:30:00 | Hospital-A | ICU | 4 | 4 | 1 |