Interrogazione senza ciclo WHILE


18

Abbiamo una tabella degli appuntamenti come mostrato di seguito. Ogni appuntamento deve essere classificato come "Nuovo" o "Seguito". Qualsiasi appuntamento (per un paziente) entro 30 giorni dal primo appuntamento (di quel paziente) è Follow-up. Dopo 30 giorni, l'appuntamento è di nuovo "Nuovo". Qualsiasi appuntamento entro 30 giorni diventa "Followup".

Attualmente sto facendo questo digitando while loop.
Come raggiungere questo obiettivo senza ciclo WHILE?

inserisci qui la descrizione dell'immagine

tavolo

CREATE TABLE #Appt1 (ApptID INT, PatientID INT, ApptDate DATE)
INSERT INTO #Appt1
SELECT  1,101,'2020-01-05' UNION
SELECT  2,505,'2020-01-06' UNION
SELECT  3,505,'2020-01-10' UNION
SELECT  4,505,'2020-01-20' UNION
SELECT  5,101,'2020-01-25' UNION
SELECT  6,101,'2020-02-12'  UNION
SELECT  7,101,'2020-02-20'  UNION
SELECT  8,101,'2020-03-30'  UNION
SELECT  9,303,'2020-01-28' UNION
SELECT  10,303,'2020-02-02' 

Non riesco a vedere la tua immagine, ma voglio confermare, se ci sono 3 appuntamenti, uno ogni 20 giorni l'uno dall'altro, l'ultimo è ancora "follow-up" giusto, perché anche se sono trascorsi più di 30 giorni dal primo, è ancora meno di 20 giorni dalla metà. È vero?
pwilcox,

@pwilcox No. Il terzo sarà il nuovo appuntamento come mostrato nell'immagine
LCJ

Mentre il fast_forwardcursore loop over sarebbe probabilmente l'opzione migliore, per quanto riguarda le prestazioni.
David Markודו Markovitz

Risposte:


14

È necessario utilizzare la query ricorsiva.

Il periodo di 30 giorni viene conteggiato a partire da prev (e no, non è possibile farlo senza ricorsione / aggiornamento / loop stravaganti). Questo è il motivo per cui tutte le risposte esistenti utilizzando solo ROW_NUMBERnon sono riuscite.

WITH f AS (
  SELECT *, rn = ROW_NUMBER() OVER(PARTITION BY PatientId ORDER BY ApptDate) 
  FROM Appt1
), rec AS (
  SELECT Category = CAST('New' AS NVARCHAR(20)), ApptId, PatientId, ApptDate, rn, startDate = ApptDate
  FROM f
  WHERE rn = 1
  UNION ALL
  SELECT CAST(CASE WHEN DATEDIFF(DAY,  rec.startDate,f.ApptDate) <= 30 THEN N'FollowUp' ELSE N'New' END AS NVARCHAR(20)), 
         f.ApptId,f.PatientId,f.ApptDate, f.rn,
         CASE WHEN DATEDIFF(DAY, rec.startDate, f.ApptDate) <= 30 THEN rec.startDate ELSE f.ApptDate END
  FROM rec
  JOIN f
    ON rec.rn = f.rn - 1
   AND rec.PatientId = f.PatientId
)
SELECT ApptId, PatientId, ApptDate, Category
FROM rec
ORDER BY PatientId, ApptDate;  

db <> demo violino

Produzione:

+---------+------------+-------------+----------+
| ApptId  | PatientId  |  ApptDate   | Category |
+---------+------------+-------------+----------+
|      1  |       101  | 2020-01-05  | New      |
|      5  |       101  | 2020-01-25  | FollowUp |
|      6  |       101  | 2020-02-12  | New      |
|      7  |       101  | 2020-02-20  | FollowUp |
|      8  |       101  | 2020-03-30  | New      |
|      9  |       303  | 2020-01-28  | New      |
|     10  |       303  | 2020-02-02  | FollowUp |
|      2  |       505  | 2020-01-06  | New      |
|      3  |       505  | 2020-01-10  | FollowUp |
|      4  |       505  | 2020-01-20  | FollowUp |
+---------+------------+-------------+----------+

Come funziona:

  1. f - ottieni il punto di partenza (ancora - per ogni PatientId)
  2. rec - ricursibe parte, se la differenza tra il valore corrente e prev è> 30 cambia la categoria e il punto di partenza, nel contesto di PatientId
  3. Principale: visualizza i risultati ordinati

Classe simile:

SUM condizionale su Oracle : limitazione di una funzione con finestra

Finestra della sessione (Azure Stream Analytics)

Esecuzione totale fino a quando la condizione specifica è vera - Aggiornamento stravagante


appendice

Non usare mai questo codice in produzione!

Ma un'altra opzione, che vale la pena menzionare oltre a usare cte, è usare la tabella temporanea e aggiornare in "round"

Potrebbe essere fatto in un round "singolo" (aggiornamento stravagante):

CREATE TABLE Appt_temp (ApptID INT , PatientID INT, ApptDate DATE, Category NVARCHAR(10))

INSERT INTO Appt_temp(ApptId, PatientId, ApptDate)
SELECT ApptId, PatientId, ApptDate
FROM Appt1;

CREATE CLUSTERED INDEX Idx_appt ON Appt_temp(PatientID, ApptDate);

Query:

DECLARE @PatientId INT = 0,
        @PrevPatientId INT,
        @FirstApptDate DATE = NULL;

UPDATE Appt_temp
SET  @PrevPatientId = @PatientId
    ,@PatientId     = PatientID 
    ,@FirstApptDate = CASE WHEN @PrevPatientId <> @PatientId THEN ApptDate
                           WHEN DATEDIFF(DAY, @FirstApptDate, ApptDate)>30 THEN ApptDate
                           ELSE @FirstApptDate
                      END
    ,Category       = CASE WHEN @PrevPatientId <> @PatientId THEN 'New'
                           WHEN @FirstApptDate = ApptDate THEN 'New'
                           ELSE 'FollowUp' 
                      END
FROM Appt_temp WITH(INDEX(Idx_appt))
OPTION (MAXDOP 1);

SELECT * FROM  Appt_temp ORDER BY PatientId, ApptDate;

db <> fiddle Quirky update


1
la tua logica è molto simile alla mia. Puoi descrivere differenze significative?
pwilcox,

@pwilcox Quando ho scritto questa risposta, tutti quelli esistenti stavano usando un semplice row_number che non funzionava, ecco perché ho fornito la mia versione
Lukasz Szozda

Sì, sono stato troppo veloce con la risposta. Grazie per averci commentato.
Irdis

2
Credo che rcte sia l'unica soluzione per questo fino a quando il server SQL non implementerà correttamente la RANGE x PRECEDINGclausola.
Salman A

1
L'aggiornamento stravagante di @LCJ si basa su comportamenti "non documentati" e potrebbe cambiare in qualsiasi momento senza preavviso ( red-gate.com/simple-talk/sql/learn-sql-server/… )
Lukasz Szozda

5

Potresti farlo con un cte ricorsivo. Si consiglia di ordinare prima per data ApptDate per ciascun paziente. Ciò può essere realizzato da un cte run-of-the-mill.

Quindi, nella parte di ancoraggio del cte ricorsivo, selezionare il primo ordine per ciascun paziente, contrassegnare lo stato come "nuovo" e anche contrassegnare l'apptDate come data del record "nuovo" più recente.

Nella parte ricorsiva del tuo cte ricorsivo, incrementa all'appuntamento successivo, calcola la differenza in giorni tra l'appuntamento attuale e la 'nuova' data dell'appuntamento più recente. Se è maggiore di 30 giorni, contrassegnalo come "nuovo" e reimposta la data del nuovo appuntamento più recente. Altrimenti contrassegnalo come "follow-up" e passa i giorni esistenti dalla nuova data dell'appuntamento.

Infine, nella query di base, basta selezionare le colonne desiderate.

with orderings as (

    select       *, 
                 rn = row_number() over(
                     partition by patientId 
                     order by apptDate
                 ) 
    from         #appt1 a

),

markings as (

    select       apptId, 
                 patientId, 
                 apptDate, 
                 rn, 
                 type = convert(varchar(10),'new'),
                 dateOfNew = apptDate
    from         orderings 
    where        rn = 1

    union all
    select       o.apptId, o.patientId, o.apptDate, o.rn,
                 type = convert(varchar(10),iif(ap.daysSinceNew > 30, 'new', 'follow up')),
                 dateOfNew = iif(ap.daysSinceNew > 30, o.apptDate, m.dateOfNew)
    from         markings m
    join         orderings o 
                     on m.patientId = o.patientId 
                     and m.rn + 1 = o.rn
    cross apply  (select daysSinceNew = datediff(day, m.dateOfNew, o.apptDate)) ap

)

select    apptId, patientId, apptDate, type
from      markings
order by  patientId, rn;

Devo dire che inizialmente ho eliminato questa risposta perché la risposta di Abhijeet Khandagale sembrava soddisfare le tue esigenze con una query più semplice (dopo averla rielaborata un po '). Ma con il tuo commento a lui sulle tue esigenze aziendali e i tuoi dati di esempio aggiunti, ho cancellato il mio perché credo che questo soddisfi le tue esigenze.


4

Non sono sicuro che sia esattamente quello che hai implementato. Ma un'altra opzione, che vale la pena menzionare oltre a usare cte, è usare la tabella temporanea e aggiornarla in "round". Quindi aggiorneremo la tabella temporanea mentre tutti gli stati non sono impostati correttamente e creeremo i risultati in modo iterativo. Possiamo controllare il numero di iterazioni usando semplicemente una variabile locale.

Quindi abbiamo diviso ogni iterazione in due fasi.

  1. Imposta tutti i valori di follow-up vicini a Nuovi record. È abbastanza facile da fare semplicemente usando il filtro giusto.
  2. Per il resto dei record che non hanno lo stato impostato possiamo selezionare prima nel gruppo con lo stesso PatientID. E dire che sono nuovi poiché non elaborati dal primo stadio.

Così

CREATE TABLE #Appt2 (ApptID INT, PatientID INT, ApptDate DATE, AppStatus nvarchar(100))

select * from #Appt1
insert into #Appt2 (ApptID, PatientID, ApptDate, AppStatus)
select a1.ApptID, a1.PatientID, a1.ApptDate, null from #Appt1 a1
declare @limit int = 0;

while (exists(select * from #Appt2 where AppStatus IS NULL) and @limit < 1000)
begin
  set @limit = @limit+1;
  update a2
  set
    a2.AppStatus = IIF(exists(
        select * 
        from #Appt2 a 
        where 
          0 > DATEDIFF(day, a2.ApptDate, a.ApptDate) 
          and DATEDIFF(day, a2.ApptDate, a.ApptDate) > -30 
          and a.ApptID != a2.ApptID 
          and a.PatientID = a2.PatientID
          and a.AppStatus = 'New'
          ), 'Followup', a2.AppStatus)
  from #Appt2 a2

  --select * from #Appt2

  update a2
  set a2.AppStatus = 'New'
  from #Appt2 a2 join (select a.*, ROW_NUMBER() over (Partition By PatientId order by ApptId) rn from (select * from #Appt2 where AppStatus IS NULL) a) ar
  on a2.ApptID = ar.ApptID
  and ar.rn = 1

  --select * from #Appt2

end

select * from #Appt2 order by PatientID, ApptDate

drop table #Appt1
drop table #Appt2

Aggiornare. Leggi il commento fornito da Lukasz. È di gran lunga più intelligente. Lascio la mia risposta solo come idea.


4

Credo che l'espressione comune ricorsiva sia un ottimo modo per ottimizzare le query evitando i loop, ma in alcuni casi può portare a cattive prestazioni e dovrebbe essere evitata se possibile.

Uso il codice qui sotto per risolvere il problema e testarlo con più valori, ma ti incoraggio a testarlo anche con i tuoi dati reali.

WITH DataSource AS
(
    SELECT *
          ,CEILING(DATEDIFF(DAY, MIN([ApptDate]) OVER (PARTITION BY [PatientID]), [ApptDate]) * 1.0 / 30 + 0.000001) AS [GroupID]
    FROM #Appt1
)
SELECT *
     ,IIF(ROW_NUMBER() OVER (PARTITION BY [PatientID], [GroupID] ORDER BY [ApptDate]) = 1, 'New', 'Followup')
FROM DataSource
ORDER BY [PatientID]
        ,[ApptDate];

inserisci qui la descrizione dell'immagine

L'idea è piuttosto semplice: voglio separare i record in gruppo (30 giorni), in quale gruppo è il record più piccolo new, gli altri lo sono follow ups. Controlla come viene costruita la dichiarazione:

SELECT *
      ,DATEDIFF(DAY, MIN([ApptDate]) OVER (PARTITION BY [PatientID]), [ApptDate])
      ,DATEDIFF(DAY, MIN([ApptDate]) OVER (PARTITION BY [PatientID]), [ApptDate]) * 1.0 / 30
      ,CEILING(DATEDIFF(DAY, MIN([ApptDate]) OVER (PARTITION BY [PatientID]), [ApptDate]) * 1.0 / 30 + 0.000001) 
FROM #Appt1
ORDER BY [PatientID]
        ,[ApptDate];

inserisci qui la descrizione dell'immagine

Così:

  1. in primo luogo, stiamo ottenendo la prima data, per ciascun gruppo e calcolando le differenze in giorni con quella corrente
  2. quindi, vogliamo ottenere gruppi - * 1.0 / 30viene aggiunto
  3. per quanto riguarda 30, 60, 90, ecc. giorni stiamo ottenendo un numero intero e volevamo iniziare un nuovo periodo, ho aggiunto + 0.000001; inoltre, stiamo usando la funzione soffitto per ottenere ilsmallest integer greater than, or equal to, the specified numeric expression

Questo è tutto. Avendo un tale gruppo, usiamo semplicemente ROW_NUMBERper trovare la nostra data di inizio e renderla come newe lasciando il resto come follow ups.


2
Bene, la domanda è un po 'diversa e questo approccio è una semplificazione eccessiva. Ma è un bell'esempio su come implementare la finestra a caduta
Lukasz Szozda il

Riguarda anche le prestazioni. Credo che la ricorsività dovrebbe essere più lenta.
Gotqn

3

Con il dovuto rispetto per tutti e in IMHO,

There is not much difference between While LOOP and Recursive CTE in terms of RBAR

Non c'è molto guadagno in termini di prestazioni durante l'utilizzo Recursive CTEe Window Partition functiontutto in uno.

Appiddovrebbe essere int identity(1,1), o dovrebbe essere in costante aumento clustered index.

Oltre ad altri benefici, assicura anche che tutte le file successive APPDatedi quel paziente debbano essere maggiori.

In questo modo puoi facilmente giocare con la APPIDtua query che sarà più efficiente di mettere inequalityoperatore come>, <in APPDate. Mettere l' inequalityoperatore come>, <in APPID aiuterà Sql Optimizer.

Inoltre ci dovrebbero essere due colonne di date nella tabella come

APPDateTime datetime2(0) not null,
Appdate date not null

Poiché queste sono le colonne più importanti nella tabella più importante, quindi non molto cast, converti.

Quindi Non clustered indexpuò essere creato su Appdate

Create NonClustered index ix_PID_AppDate_App  on APP (patientid,APPDate) include(other column which is not i predicate except APPID)

Prova il mio script con altri dati di esempio e fammi sapere per quali dati di esempio non funziona. Anche se non funziona, sono sicuro che può essere corretto nella mia logica di script stessa.

CREATE TABLE #Appt1 (ApptID INT, PatientID INT, ApptDate DATE)
INSERT INTO #Appt1
SELECT  1,101,'2020-01-05'  UNION ALL
SELECT  2,505,'2020-01-06'  UNION ALL
SELECT  3,505,'2020-01-10'  UNION ALL
SELECT  4,505,'2020-01-20'  UNION ALL
SELECT  5,101,'2020-01-25'  UNION ALL
SELECT  6,101,'2020-02-12'  UNION ALL
SELECT  7,101,'2020-02-20'  UNION ALL
SELECT  8,101,'2020-03-30'  UNION ALL
SELECT  9,303,'2020-01-28'  UNION ALL
SELECT  10,303,'2020-02-02' 

;With CTE as
(
select a1.* ,a2.ApptDate as NewApptDate
from #Appt1 a1
outer apply(select top 1 a2.ApptID ,a2.ApptDate
from #Appt1 A2 
where a1.PatientID=a2.PatientID and a1.ApptID>a2.ApptID 
and DATEDIFF(day,a2.ApptDate, a1.ApptDate)>30
order by a2.ApptID desc )A2
)
,CTE1 as
(
select a1.*, a2.ApptDate as FollowApptDate
from CTE A1
outer apply(select top 1 a2.ApptID ,a2.ApptDate
from #Appt1 A2 
where a1.PatientID=a2.PatientID and a1.ApptID>a2.ApptID 
and DATEDIFF(day,a2.ApptDate, a1.ApptDate)<=30
order by a2.ApptID desc )A2
)
select  * 
,case when FollowApptDate is null then 'New' 
when NewApptDate is not null and FollowApptDate is not null 
and DATEDIFF(day,NewApptDate, FollowApptDate)<=30 then 'New'
else 'Followup' end
 as Category
from cte1 a1
order by a1.PatientID

drop table #Appt1

3

Sebbene non sia chiaramente affrontato nella domanda, è facile capire che le date degli appuntamenti non possono essere semplicemente classificate per gruppi di 30 giorni. Non ha senso per gli affari. E non puoi nemmeno usare l'ID appt. Si può prendere un nuovo appuntamento oggi per2020-09-06. Ecco come risolvo questo problema. Innanzitutto, ottieni il primo appuntamento, quindi calcola la differenza di data tra ogni appuntamento e la prima appt. Se è 0, impostare su "Nuovo". Se <= 30 'Followup'. Se> 30, impostare come "Indeciso" e fare il giro successivo controllare fino a quando non c'è più "Indeciso". E per questo, hai davvero bisogno di un ciclo while, ma non scorre attraverso ogni data dell'appuntamento, piuttosto solo alcuni set di dati. Ho controllato il piano di esecuzione. Anche se ci sono solo 10 righe, il costo della query è significativamente inferiore rispetto a quello che utilizza CTE ricorsivo, ma non così basso come il metodo dell'addendum di Lukasz Szozda.

IF OBJECT_ID('tempdb..#TEMPTABLE') IS NOT NULL DROP TABLE #TEMPTABLE
SELECT ApptID, PatientID, ApptDate
    ,CASE WHEN (DATEDIFF(DAY, MIN(ApptDate) OVER (PARTITION BY PatientID), ApptDate) = 0) THEN 'New' 
    WHEN (DATEDIFF(DAY, MIN(ApptDate) OVER (PARTITION BY PatientID), ApptDate) <= 30) THEN 'Followup'
    ELSE 'Undecided' END AS Category
INTO #TEMPTABLE
FROM #Appt1

WHILE EXISTS(SELECT TOP 1 * FROM #TEMPTABLE WHERE Category = 'Undecided') BEGIN
    ;WITH CTE AS (
        SELECT ApptID, PatientID, ApptDate 
            ,CASE WHEN (DATEDIFF(DAY, MIN(ApptDate) OVER (PARTITION BY PatientID), ApptDate) = 0) THEN 'New' 
            WHEN (DATEDIFF(DAY, MIN(ApptDate) OVER (PARTITION BY PatientID), ApptDate) <= 30) THEN 'Followup'
            ELSE 'Undecided' END AS Category    
        FROM #TEMPTABLE
        WHERE Category = 'Undecided'
    )
    UPDATE #TEMPTABLE
    SET Category = CTE.Category
    FROM #TEMPTABLE t
        LEFT JOIN CTE ON CTE.ApptID = t.ApptID
    WHERE t.Category = 'Undecided'
END

SELECT ApptID, PatientID, ApptDate, Category 
FROM #TEMPTABLE

2

Spero che questo ti possa aiutare.

WITH CTE AS
(
    SELECT #Appt1.*, RowNum = ROW_NUMBER() OVER (PARTITION BY PatientID ORDER BY ApptDate, ApptID) FROM #Appt1
)

SELECT A.ApptID , A.PatientID , A.ApptDate ,
Expected_Category = CASE WHEN (DATEDIFF(MONTH, B.ApptDate, A.ApptDate) > 0) THEN 'New' 
WHEN (DATEDIFF(DAY, B.ApptDate, A.ApptDate) <= 30) then 'Followup' 
ELSE 'New' END
FROM CTE A
LEFT OUTER JOIN CTE B on A.PatientID = B.PatientID 
AND A.rownum = B.rownum + 1
ORDER BY A.PatientID, A.ApptDate

Grazie @ x00 per aver modificato il codice in formato leggibile, sto usando il mio cellulare per inviare risposte, quindi non sono stato in grado di fornire rientri adeguati.
Abhijeet Khandagale

Penso che questa sia essenzialmente la risposta giusta. Ma è una risposta di scarsa qualità in quanto non è spiegato e il codice ha una query esterna inutile quando una modifica della parte interna andrà bene. Se riesci a risolvere questi problemi, sarò felice di votarti.
pwilcox,

1
@pwilcox, grazie per il prezioso suggerimento, ho modificato la risposta e l'ho pubblicata fin d'ora. Mentre viaggio e non ho un laptop con me, pubblicherò spiegazioni tra un giorno o due.
Abhijeet Khandagale

1
@AbhijeetKhandagale Questo non soddisfa completamente i requisiti aziendali. Ho aggiunto uno scenario di errore nella domanda. Per il paziente 303, il 2 febbraio l'appuntamento dovrebbe essere di follow-up; ma la tua query dice che è "Nuovo"
LCJ

1

Potresti usare una Casedichiarazione .

select 
      *, 
      CASE 
          WHEN DATEDIFF(d,A1.ApptDate,A2.ApptDate)>30 THEN 'New' 
          ELSE 'FollowUp' 
      END 'Category'
from 
      (SELECT PatientId, MIN(ApptId) 'ApptId', MIN(ApptDate) 'ApptDate' FROM #Appt1 GROUP BY PatientID)  A1, 
      #Appt1 A2 
where 
     A1.PatientID=A2.PatientID AND A1.ApptID<A2.ApptID

La domanda è: questa categoria dovrebbe essere assegnata in base all'appuntamento iniziale o a quello precedente? Cioè, se un paziente ha avuto tre appuntamenti, dovremmo confrontare il terzo appuntamento con il primo o il secondo?

Il tuo problema afferma il primo, ed è così che ho risposto. In caso contrario, ti consigliamo di utilizzarlo lag.

Inoltre, tieni presente che DateDiffnon fa eccezione per i fine settimana. Se questo dovrebbe essere solo nei giorni feriali, dovrai creare la tua funzione scalare-valutata.


1
Questo non collega due appuntamenti sequenziali, collega circa 1 a tutti gli appuntamenti seguenti e calcola i giorni intermedi per tutti. Restituiresti troppi record in questo modo, poiché l'appt 1 ora ha una relazione con 2, 3, 4, l'appt 2 ha una relazione con 3, 4 ...
steenbergh,

Buon punto. Ho aggiornato la mia risposta per fare una sottoselezione per A1.
utente

1
Non dà il risultato atteso. L'appuntamento del 20 febbraio dovrebbe essere "Followup"
LCJ

La domanda non è chiara ... La descrizione del poster è questa: "Qualsiasi appuntamento (per un paziente) entro 30 giorni dal primo appuntamento (di quel paziente) è Follow-up. Dopo 30 giorni, l'appuntamento è di nuovo" Nuovo ". Qualsiasi appuntamento entro 30 giorni diventa "Followup". " Il 5 gennaio è sicuramente a più di 30 giorni dal 20 febbraio, ovvero Nuovo. Tuttavia, non sono trascorsi 30 giorni dal 12 febbraio. Offro una soluzione a ciò che ha scritto, non alla tabella fornita. Se l'utente desidera allinearsi con ciò che la tabella fornisce, dovrebbe usare il ritardo. Dovrebbero anche chiarire ...
utente

1

usando la funzione Lag


select  apptID, PatientID , Apptdate ,  
    case when date_diff IS NULL THEN 'NEW' 
         when date_diff < 30 and (date_diff_2 IS NULL or date_diff_2 < 30) THEN  'Follow Up'
         ELSE 'NEW'
    END AS STATUS FROM 
(
select 
apptID, PatientID , Apptdate , 
DATEDIFF (day,lag(Apptdate) over (PARTITION BY PatientID order by ApptID asc),Apptdate) date_diff ,
DATEDIFF(day,lag(Apptdate,2) over (PARTITION BY PatientID order by ApptID asc),Apptdate) date_diff_2
  from #Appt1
) SRC

Demo -> https://rextester.com/TNW43808


2
Funziona con i dati di esempio correnti ma potrebbe produrre risultati errati dati dati di esempio diversi. Anche se usi apptDatecome order bycolonna della lagfunzione (che dovresti davvero come ID non è una garanzia di nulla), può comunque essere facilmente rotto introducendo ulteriori appuntamenti di follow-up. Guarda questa demo di Rextester per esempio. Buona prova, però ...
Zohar Peled

Grazie. Avrebbe dovuto usare la data anziché l'ID. Ma perché è sbagliato per apptID = 6 25.01.2020 - 12.02.2020 -> 18 giorni -> follow-up.
Digvijay S

2
Perché dovrebbe essere un Newe non un FollowUp. Sono trascorsi più di 30 giorni dal primo appuntamento di quel paziente ... Dovresti contare 30 giorni da ogni Newappuntamento e poi usare di Newnuovo un ...
Zohar Peled

Sì. Grazie. :( È necessario crearne uno nuovo per verificare un periodo di date valido.
Digvijay S

1
with cte
as
(
select 
tmp.*, 
IsNull(Lag(ApptDate) Over (partition by PatientID Order by  PatientID,ApptDate),ApptDate) PriorApptDate
 from #Appt1 tmp
)
select 
PatientID, 
ApptDate, 
PriorApptDate, 
DateDiff(d,PriorApptDate,ApptDate) Elapsed,
Case when DateDiff(d,PriorApptDate,ApptDate)>30 
or DateDiff(d,PriorApptDate,ApptDate)=0 then 'New' else 'Followup'   end Category   from cte

Il mio è corretto. Gli autori non erano corretti, vedi trascorso

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.