2016-04-23 33 views
5

Ho un sottoinsieme di record che assomigliano a questo:Come ottenere la prossima data minima che non è tra 30 giorni e utilizzare come punto di riferimento in SQL?

ID DATE 
A 2015-09-01 
A 2015-10-03 
A 2015-10-10 
B 2015-09-01 
B 2015-09-10 
B 2015-10-03 
... 

Per ogni ID la prima data minima è il primo record di indice. Ora devo escludere i casi entro 30 giorni dal record dell'indice e qualsiasi record con una data superiore a 30 giorni diventa un altro record di indice.

Ad esempio, per ID A, 2015-09-01 e 2015-10-03 sono entrambi record di indice e verrebbero mantenuti poiché sono separati da più di 30 giorni. 2015-10-10 verrebbe eliminato perché è entro 30 giorni dal secondo caso indice.

Per ID B, 2015-09-10 verrebbe eliminato e NON sarebbe un caso indice perché è entro 30 giorni dal primo record dell'indice. Il 2015-10-03 verrà mantenuto perché è superiore a 30 giorni del primo record dell'indice e sarà considerato il secondo caso indice.

L'output dovrebbe essere simile a questo:

ID DATE 
A 2015-09-01 
A 2015-10-03 
B 2015-09-01 
B 2015-10-03 

Come faccio a fare questo in SQL Server 2012? Non c'è limite al numero di date che un ID può avere, potrebbe essere da 1 a 5 o più. Sono abbastanza semplice con SQL quindi qualsiasi aiuto sarebbe molto apprezzato.

+0

Stiamo ancora affrontando il problema? –

risposta

2

lavorando come nel tuo esempio, #test è la vostra tabella con i dati:

;with cte1 
as 
(
    select 
     ID, Date, 
     row_number()over(partition by ID order by Date) groupID 
    from #test 
), 
cte2 
as 
(
    select ID, Date, Date as DateTmp, groupID, 1 as getRow from cte1 where groupID=1 
    union all 
    select 
     c1.ID, 
     c1.Date, 
     case when datediff(Day, c2.DateTmp, c1.Date) > 30 then c1.Date else c2.DateTmp end as DateTmp, 
     c1.groupID, 
     case when datediff(Day, c2.DateTmp, c1.Date) > 30 then 1 else 0 end as getRow 
    from cte1 c1 
    inner join cte2 c2 on c2.groupID+1=c1.groupID and c2.ID=c1.ID 
) 
select ID, Date from cte2 where getRow=1 order by ID, Date 
+0

Questo ha funzionato perfettamente !!! Grazie mille! Molto apprezzato =) – KChan

-1

Prova questa soluzione.

Sample demo

with diffs as (
select t1.id,t1.dt strtdt,t2.dt enddt,datediff(dd,t1.dt,t2.dt) daysdiff 
from t t1 
join t t2 on t1.id=t2.id and t1.dt<t2.dt 
) 
, y as (
select id,strtdt,enddt 
from (
select id,strtdt,enddt,row_number() over(partition by id,strtdt order by daysdiff) as rn 
from diffs 
where daysdiff > 30 
) x 
where rn=1 
) 
,z as (
select *,coalesce(lag(enddt) over(partition by id order by strtdt),strtdt) prevend 
from y) 
select id,strtdt from z where strtdt=prevend 
union 
select id,enddt from z where strtdt=prevend 
+0

chiedo se il motivo può essere spiegato per il downvote –

+0

C'è stata una raffica di downvotes in qualche modo. –

-1

La logica spiegato in questione è sbagliato, in un unico posto, hai detto prendere il primo record indice e in successivo posto hai considerato registrare immediato ..

Questo funziona per record immediati:

with cte 
as 
(
select *, ROW_NUMBER() over (partition by id order by datee) as rownum 
from #test 
) 
select *,datediff(day,beforedate,datee) 
from cte t1 
cross apply 
(Select isnull(max(Datee),t1.datee) as beforedate from cte t2 where t1.id =t2.id and t2.rownum<t1.rownum) b 
where datediff(day,beforedate,datee)= 0 or datediff(day,beforedate,datee)>=30 

Questo wo RKS per registrare di base costante:

select *,datediff(day,basedate,datee) from #test t1 
cross apply 
(select min(Datee) as basedate from #test t2 where t1.id=t2.id)b 
where datediff(day,basedate,datee)>=30 or datediff(day,basedate,datee)=0 
+0

@downvoters: si prega di lasciare un commento sul motivo per cui questo è stato downvoted – TheGameiswar

0
select * from 
    (
    select ID,DATE_, case when DATE_DIFF is null then 1 when date_diff>30 then 1 else 0 end comparison from 
     (
      select ID, DATE_ ,DATE_-LAG(DATE_, 1) OVER (PARTITION BY ID ORDER BY DATE_) date_diff from trial 
     ) 
    ) 
    where comparison=1 order by ID,DATE_; 

provato in Oracle Database. Funzionalità simili esistono anche in SQL Server.

Sto raggruppando per colonna Id e in base al campo DATE, sto confrontando la data nel campo corrente con il suo campo precedente. La prima riga di un determinato ID utente restituirebbe null, e il primo campo è richiesto nel nostro output come primo indice. Per tutti gli altri campi, ritorniamo 1 quando la differenza di data rispetto al campo precedente è maggiore di 30.

Lag function in transact sql

Case function in transact sql

+0

'AS' prima degli alias obbligatori nel server SQL?In tal caso ORDER BY DATA_) AS date_diff –

+0

Per il server SQL: selezionare * da ( selezionare ID, DATA_, caso in cui date_diff è nullo quindi 1 quando date_diff> 30 allora 1 altrimenti 0 estremità AS confronto ( selezionare ID , DATE_, DATE_-LAG (DATE_, 1) OVER (PARTITION BY ID ORDER BY DATE_) AS date_diff dalla versione di prova ) ) dove confronto = 1 ordine per ID, DATE_; –

+0

Grazie, ho provato questo ma ho ottenuto un errore di sintassi vicino a ')'. Un altro modo di porre la mia domanda è, come posso selezionare solo i record che sono> = 30 giorni di distanza per ogni ID? Ignorando o rimuovendo tutti quelli in mezzo. – KChan