Вычитание между рядами - PullRequest
3 голосов
/ 27 марта 2019

У меня есть код ниже, написанный для вычитания из разных строк в 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

Я пытаюсь подсчитать время, в течение которого неиспользуемое пространство между каждым пациентом, который заканчивает лечение, и каждым новым пациентом, который приходит, но в этом случае я получаю разницу во времени между пациентами в один и тот же день (т.е. не хочу разницы между пациентом А и пациентом С)

Я также хотел бы иметь возможность добавлять описания случаев, чтобы, если разница превышала определенную сумму (скажем, 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 ]

1 голос
/ 27 марта 2019

Вам нужно оценить свою комнату / дату, чтобы вы могли получить подробности из следующей записи. Примерно так:

 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
0 голосов
/ 27 марта 2019

EDIT

Я пошел еще дальше и дал вам возможность найти среднее время между использованием комнаты, с возможностью установить интервал игнорирования.

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

Результаты :

| 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

Результаты

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

Если вы хотите отфильтровать ИЛИ посещения дольше, чем определенное время, раскомментируйте AND DATEDIFF(...)... в приведенном выше запросе и используйте соответствующее число SECONDS, которое вы хотите, чтобы разница была.

...