Sql 创建由多个列和连续日期分区的序列

Sql 创建由多个列和连续日期分区的序列,sql,sql-server,sql-server-2005,Sql,Sql Server,Sql Server 2005,我试图弄清楚如何创建一个由多个列划分的序列,其中序列必须重新设置,而另一个(基于日期的)列是不连续的 问题:医院ADT(入院/出院/转院)事件发生在特定时间点,但我们希望将这些事件转化为具有持续时间(时间跨度)的活动,即我们有开始日期,但没有结束日期,这是基于下一个适当的ADT事件。我们已经在代码中实现了这一点,但也希望在SQL中实现这一点以提高性能。e、 g.查找在ICU待了48小时以上的患者 我们需要记录六个不同级别的现场位置的持续时间:设施、护理点、建筑、地板、房间和床 例如: Strea

我试图弄清楚如何创建一个由多个列划分的序列,其中序列必须重新设置,而另一个(基于日期的)列是不连续的

问题:医院ADT(入院/出院/转院)事件发生在特定时间点,但我们希望将这些事件转化为具有持续时间(时间跨度)的活动,即我们有开始日期,但没有结束日期,这是基于下一个适当的ADT事件。我们已经在代码中实现了这一点,但也希望在SQL中实现这一点以提高性能。e、 g.查找在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
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
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    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
因此,对于每个事件,我们想知道它们在每个特定的站点位置停留了多长时间。每个流中最后一个活动的结束日期要么为空(仍然是住院患者),要么为患者出院日期

以下是我当前的解决方案:

-- 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    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
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
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    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
然后根据序列创建持续时间:

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    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
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
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    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


我已经兜圈子有一段时间了:)谢谢你的帮助,谢谢

如果我正确理解您的问题,您需要连续的
行号()。您可以使用stream
row_NUMBER()
和单个序列之间的行号差异来生成一个组,在该组上为设施和护理点订购行号

由于这些不是使用
设施
护理点
直接分组的,而是根据顺序进行分组的,因此如果患者再次切换回同一设施或护理点,则会重置顺序

用这样的东西

您可以根据需要根据这些顺序生成日期范围

输出

| 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 |

您能否澄清所提供的表格中哪些是源数据,哪些是预期结果。另外,请添加一个带有SQL Server版本的标记。我没有添加版本标记,因为它是SQL Server>=2005,但现在已将其添加为基线。如果不清楚,很抱歉,但ADT_事件和ADT_流是源表,ADT_活动表正从它们生成。为了简洁起见,我省略了一些其他代码,但主要是处理要更新的事件和流的内务处理。您能否清楚地显示您的样本数据是什么样子的,以及基于该样本数据的最终结果应该是什么。现在问题中有5个表,其中一些有
Stream=3
,一些没有。这令人困惑。关于版本:SQL Server 2012+具有类似于
LEAD
LAG
的功能,这可能会大大有助于计算持续时间。没问题,我将创建一个SQLFIDLE模式和一些测试数据。ughai击败了我:)正在处理,谢谢!我唯一需要改变的是在每个站点位置的CTE分区上添加一个ISNULL检查,如果为null,则使用活动PK,因为位置可能并不总是被设置,所以必须在null.FWIW上重置,进一步的测试发现了另一个问题,我可能没有对此进行充分的解释,但每个站点位置都有一个层次结构,因此,我必须将CTE中的每个较低位置划分为较高级别的位置,因为它们可以共享。例如,ICU的同一个密钥可能位于两个不同的设施中,因此您必须按设施和护理点对护理点位置进行划分,以此类推,划分不同的级别。