行之间相减

时间:2019-03-27 18:12:16

标签: sql sql-server tsql sql-server-2012

我编写了以下代码,以从SQL的不同行中减去(但仅从具有相同Room和Date的行中减去),以获得行之间的时间差。它可以工作,但是错过了一些所需的方案。

我只想彼此减去最近的日期。在下面,您会看到我的结果的开始。

     PatientName PatientName  OutTime   InTime  Room    Room    Value
     Patient A   Patient B     45:00.0  55:00.0 OR 1    OR 1    10
     Patient A   Patient C     45:00.0  55:00.0 OR 1    OR 1    130
     Patient B   Patient C     00:00.0  55:00.0 OR 1    OR 1    55

我正在尝试计算每个完成治疗的患者与每个新来的患者之间的闲置时间,但是在这种情况下,我得到的是同一天患者之间的每次时间差(即不希望患者A和患者C之间有区别)

我还希望能够添加个案语句,以便如果差异大于一定数量(例如90分钟),则不计入差异。

请告知。

        --This code creates the table with Dummy Data

        CREATE TABLE #OperatingRoom (
        [Date] date,
        [Room] varchar(255),
    [PatientName] varchar(255),
        [InTime] time,
        [OutTime] time,
        ); 

        INSERT INTO #OperatingRoom ([Date],[Room],[PatientName],[InTime],        [OutTime])
        VALUES ('01-01-2019', 'OR 1', 'Patient A', '08:02:00','09:45:00'),
        ('01-01-2019', 'OR 1', 'Patient B', '09:55:00','11:00:00'),
        ('01-01-2019', 'OR 1', 'Patient C', '11:55:00','14:00:00'),
        ('01-02-2019', 'OR 1', 'Patient D', '08:59:00','09:14:00'),
        ('01-02-2019', 'OR 1', 'Patient E', '11:02:00','13:30:00'),
        ('01-02-2019', 'OR 2', 'Patient F', '14:02:00','16:02:00'),
        ('01-03-2019', 'OR 2', 'Patient B', '07:55:00','11:00:00'),
        ('01-03-2019', 'OR 2', 'Patient C', '11:55:00','13:00:00'),
        ('01-03-2019', 'OR 3', 'Patient D', '08:59:00','09:14:00'),
        ('01-03-2019', 'OR 2', 'Patient E', '13:02:00','13:30:00'),
        ('01-03-2019', 'OR 3', 'Patient F', '14:02:00','16:02:00')
        ;

        --This code performs the object of the query 

        SELECT 
        T1.PatientName,
        T2.PatientName,
        T1.[OutTime]
       ,T2.InTime,
        T1.Room,
        T2.Room,
        datediff(mi,T1.OutTime,T2.InTime) AS Value
        FROM #operatingroom T1
        JOIN #operatingroom T2
        ON T2.[OutTime] > T1.[InTime]
        and T1.[Date] = T2.[Date] 
        and T1.Room = T2.Room 
        and T1.PatientName <> T2.PatientName

2 个答案:

答案 0 :(得分:1)

您需要对房间/日期进行排名,以便从下一条记录中获取详细信息。像这样:

 WITH Myrooms as (
      Select  Date, 
              Room, 
              PatientName, 
              InTime,
              OutTime, 
              DENSE_RANK() OVER (PARTITION BY Room, Date ORDER BY InTime) as PatientRank 
      From #OperatingRoom )

  Select Date, 
         Room, 
         PatientName, 
         M.InTime, 
         OutTime,
         CASE WHEN DateDiff(mi,M.OutTime, aa.InTime) >90 then NULL 
         else DateDiff(mi,M.OutTime, aa.InTime) END as Value 
  from Myrooms M
  OUTER APPLY
  (Select InTime from MyRooms MM 
   WHERE MM.Room=M.Room and MM.Date=M.Date and MM.PatientRank=M.PatientRank+1) aa

答案 1 :(得分:0)

编辑

我又走了一步,为您提供了一种方法来查找两次房间使用之间的平均时间,并可以设置忽略间隔。

SQL Fiddle

查询

DECLARE @OnlyCountMinutes int 
SET @OnlyCountMinutes = 90  
DECLARE @OnlyCountSeconds int  
SET @OnlyCountSeconds = @OnlyCountMinutes*60 


SELECT s1.Room
    , AVG(secSinceLast) / 60.0 AS minutesSinceLast
FROM
(
  SELECT
       Room
     , InTime
     , OutTime
     , LEAD(InTime) OVER (PARTITION BY Room ORDER BY InTime) AS nextIn
     , LAG(OutTime) OVER (PARTITION BY Room ORDER BY OutTime) AS prevOut
     , DATEDIFF(second, LAG(OutTime) OVER (PARTITION BY Room ORDER BY OutTime), InTime) AS secSinceLast
     -- , DATEDIFF(second, outTime, LEAD(InTime) OVER (PARTITION BY Room ORDER BY InTime)) AS secUntilNext
  FROM OperatingRoom
) s1
WHERE ISNULL(s1.secSinceLast,@OnlyCountSeconds+1) < @OnlyCountSeconds
    -- AND ISNULL(s1.secUntilNext,@OnlyCountSeconds+1) < @OnlyCountSeconds
GROUP BY s1.Room
ORDER BY s1.Room

Results

| Room | minutesSinceLast |
|------|------------------|
| OR 1 |             32.5 |
| OR 2 |             28.5 |

就像我上面的建议一样,我将日期和时间合并到一个字段中。这将使我们能够跨越几天。然后,我为您声明一个变量,以将要设置的分钟数设置为可忽略的最小空闲时间。我将其转换为秒。这并不是真正需要的,尤其是如果您不跟踪秒数或不关心间隔之间有多少秒。我转而使用LAG()窗口函数(在SQL2012中也添加了),因为您实际上更关心条目之前发生的事情和条目之后发生的事情。然后,我仅使用标准聚合来计算每个房间的平均间隔(不包括您之前设置的限制)。

--------------------原始--------------------

好消息是,在SQL 2012中,您可以使用LEAD()窗口函数。

SQL Fiddle

使用上面的设置信息查询

SELECT Room
    , PatientName
    , Date
    , InTime
    , OutTime
    , nextIn
    , gapDiffInSeconds = DATEDIFF(second,OutTime,nextIn)
FROM
(
  SELECT
       PatientName
     , Room
     , [Date]
     , InTime
     , OutTime
     , nextIn     = LEAD(InTime) OVER (PARTITION BY [Room],[Date] ORDER BY [Date],[OutTime])
  FROM OperatingRoom
) s1
WHERE DATEDIFF(second,OutTime,nextIn) > 1
    -- AND DATEDIFF(second,OutTime,nextIn) < 5400 /* 60 seconds * 90 minutes = 5400 seconds */
ORDER BY Room, Date, InTime, OutTime

Results

| Room | PatientName |       Date |           InTime |          OutTime |           nextIn | gapDiffInSeconds |
|------|-------------|------------|------------------|------------------|------------------|------------------|
| OR 1 |   Patient A | 2019-01-01 | 08:02:00.0000000 | 09:45:00.0000000 | 09:55:00.0000000 |              600 |
| OR 1 |   Patient B | 2019-01-01 | 09:55:00.0000000 | 11:00:00.0000000 | 11:55:00.0000000 |             3300 |
| OR 1 |   Patient D | 2019-01-02 | 08:59:00.0000000 | 09:14:00.0000000 | 11:02:00.0000000 |             6480 |
| OR 2 |   Patient B | 2019-01-03 | 07:55:00.0000000 | 11:00:00.0000000 | 11:55:00.0000000 |             3300 |
| OR 2 |   Patient C | 2019-01-03 | 11:55:00.0000000 | 13:00:00.0000000 | 13:02:00.0000000 |              120 |
| OR 3 |   Patient D | 2019-01-03 | 08:59:00.0000000 | 09:14:00.0000000 | 14:02:00.0000000 |            17280 |

如果您想过滤掉OR访问时间超过特定时间,请在上面的查询中取消注释AND DATEDIFF(...)...,并使用适当的数量SECONDS