2017-02-10 2 views
2

Это дата пациент посетил больницу:T-SQL: список дат с самой последней предыдущей датой

NAME DISCHARGEDATE 
--------------------- 
Eva   1/1/17 
Eva   1/10/17 
Eva   2/8/17 

мне нужна список пациентов, финики посетили больницу вместе с самым последней предыдущей датой они посетили больницы, как это:

NAME DISCHARGEDATE  PREVIOUSDISCHARGEDATE 
----------------------------------------------- 
Eva   1/1/17  NULL 
Eva   1/10/17  1/1/17 
Eva   2/8/17  1/10/17 

Я пытался RowNum() и Top 1 и коррелированные подзапросы, и я просто не могу получить его. Спасибо.

Вот сценарий, я написал для реальности она возвращает посещения пациента, но «NULL» для всех полей из второй таблицы:

SELECT 
    ad.Name, 
    ad.DischargeDate, 
    PrevDisch.DischargeDate as PrevDischDate 
FROM 
    AbstractData AS ad 
LEFT JOIN 
    (SELECT TOP 1 
     DischargeDate, UnitNumber, VisitID 
    FROM 
     AbstractData AS ad2 
    WHERE 
     SourceID = 'BLD' 
     AND PtStatus in ('IN', 'INO') 
     AND DischargeDateTime > @ReadmitStartDate 
     --AND ad2.DischargeDate < ad.DischargeDate 
    ORDER BY 
     UnitNumber, DischargeDate) AS PrevDisch ON ad.UnitNumber = PrevDisch.UnitNumber 
               AND PrevDisch.DischargeDate < ad.DischargeDate            
               AND PrevDisch.DischargeDate IS NOT NULL 
WHERE 
    ad.Name = 'Eva' 
+1

какая у вас версия сиквельного сервера? – Kostya

+0

Предполагая, что 1/20/17 является опечаткой –

+0

Да, спасибо, я ее отредактировал. –

ответ

3

Вы можете использовать LAG()

Declare @YourTable table (NAME varchar(25),DISCHARGEDATE date) 
Insert Into @YourTable values 
('Eva','2017-01-01'), 
('Eva','2017-10-01'), 
('Eva','2017-02-08') 

Select A.* 
     ,PREVIOUSDISCHARGEDATE = Lag(DISCHARGEDATE,1) over (Partition By Name Order by DISCHARGEDATE) 
From @YourTable A 

Возвращает

NAME DISCHARGEDATE PREVIOUSDISCHARGEDATE 
Eva  2017-01-01  NULL 
Eva  2017-02-08  2017-01-01 
Eva  2017-10-01  2017-02-08 

Edit- Альтернатива LAG()

;with cte as (
    Select * 
      ,RN = Row_Number() over (Partition By Name Order by DISCHARGEDATE) 
    From @YourTable 
) 
Select A.* 
     ,PREVIOUSDISCHARGEDATE = B.DISCHARGEDATE 
From cte A 
Left Join cte B a.name=B.name and on A.RN=B.RN+1 
+0

Черт. Мне просто нужно это сделать. Ты подтолкнул меня на это! – MarlonRibunal

+0

@John - Ваш ответ превосходный. но можете ли вы предоставить решение без функции задержки, пожалуйста. – balaji

+0

@balaji Посмотреть обновленный ответ –

0

Я знаю, что Джон Cappelletti уже дал ответ, используя LAG(). Но хотелось попробовать решение с присоединением, следовательно, решение. Может быть в будущем, если кому-то понадобится его без LAG(). Это решение, похоже, немного громоздко, но оно выполняет эту задачу.

Declare @YourTable table (NAME varchar(25),DISCHARGEDATE date) 
Insert Into @YourTable values 
('Eva','2017-01-01'), 
('Eva','2017-10-01'), 
('Eva','2017-02-08') 

SELECT NAME,DISCHARGEDATE,MAX(PREVIOUS) AS PREVIOUS_DISCHARGE 
FROM 
(SELECT NAME,DISCHARGEDATE,'NULL' AS PREVIOUS 
FROM 
(SELECT NAME 
     ,DISCHARGEDATE 
     ,ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY DISCHARGEDATE) RN FROM @YourTable) M 
WHERE M.RN=1   
UNION ALL 
SELECT X.NAME,X.DISCHARGEDATE,CONVERT(VARCHAR(10),Y.DISCHARGEDATE) 
FROM 
     (SELECT NAME 
       ,DISCHARGEDATE 
       ,ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY DISCHARGEDATE) RN FROM @YourTable) X 
INNER JOIN  
     (SELECT NAME 
       ,DISCHARGEDATE 
       ,(ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY DISCHARGEDATE)-1) RN FROM @YourTable) Y  
ON X.RN > Y.RN) OUTERR 
WHERE CONVERT(VARCHAR(10),DISCHARGEDATE) <> PREVIOUS 
GROUP BY NAME,DISCHARGEDATE 
ORDER BY NAME