2016-05-10 19 views
1

Dies ist meine erste Post hier, obwohl ich ein täglicher Leser bin. :)Rekursive Abfrage mit Zeitunterschied

Ich muss einen MS SQL Server 2014 Bericht erstellen, der die Kunden zeigt, die zurückkommen, um Geschäfte mit mir in weniger als oder gleich 3 Tagen zu machen. Ich habe es mit INNER JOINS versucht, aber ich war nicht erfolgreich.

So wie ich die Lösung angenommen wird, die unterhalb der Logik:

If product is same 
    and if userId is same 
    and if action was donedeal but now is new 
    and if date diff <= 3 days 
    and if type is NOT same 
then show results 

zB meine Daten:

id orderId userId type product date  action 
1 1001 654  ordered apple 01/05/2016 new 
2 1002 889  ordered peach 01/05/2016 new 
3 1001 654  paid apple 01/05/2016 donedeal 
4 1002 889  paid peach 03/05/2016 donedeal 
5 1003 654  ordered apple 03/05/2016 new 
6 1004 889  ordered peach 04/05/2016 new 
7 1005 122  ordered apple 04/05/2016 new 
8 1006 978  ordered peach 04/05/2016 new 
9 1005 122  paid apple 04/05/2016 donedeal 
10 1007 122  ordered apple 10/05/2016 new 

Wunschergebnisse:

id orderId userId type product date  Diff 
3 1001 654  paid apple 01/05/2016 2 days 
4 1002 889  paid peach 03/05/2016 1 day 
5 1003 654  ordered apple 03/05/2016 2 days 
6 1004 889  ordered peach 04/05/2016 1 day 

Könnten Sie bitte direkt Ich zu den Funktionen, die nützlich sein können, um das zu lösen?

Vielen Dank im Voraus.

#

aktualisieren

Gordon Linoff gab mir den unten vorgeschlagen Code aber da der Typ verschieden sein musste ich den Code repliziert und führen Sie es wie unten pro und es funktionierte.

wählen t * aus (wählen t. *, max (Fall, wenn action = 'donedeal' und type = 'bezahlt' dann Enddatum) über (Partition durch Benutzer, Produkt sortiert nach Datum) als last_donedealdate von t ) t wo action = 'neu' und type = 'bestellt' Datum < dateadd (Tag, 3, last_donedealdate)

UNION ALL

wählen t. * aus (t wählen. *, max (Fall, wenn action = 'donedeal' und type = 'bestellt' dann Datum Ende) über (Partition durch Benutzer, Produkt sortiert nach Datum) als last_donedealdate von t ) t wo action = 'neuer' und type = 'bezahlt' Datum < dateadd (Tag, 3, last_donedealdate)

+1

Selbst innere Verbindung ist ein Weg zu gehen. Was hast du versucht? (Sonst könnten Sie eine GROUP BY versuchen.) – jarlh

+0

@jarlh Würde der innere Join helfen, da jede Zeile mit jeder anderen Zeile verglichen werden muss und diejenigen, die den Kriterien entsprechen (Typ, datediff, action)? Ich versuchte die GroupBy und verglich die MIN (Datum) und MAX (Datum), aber das bedeutet, dass es nur zwischen 2 Ergebnissen vergleichen wird. Es gibt Fälle, in denen mehr als 1 Übereinstimmung mit jeder Zeile vorhanden ist. – ct14

Antwort

1

Sie kann hierfür Fensterfunktionen verwenden. Verwenden Sie max() mit partition by und order by, um das letzte Fertigstellungsdatum zu erhalten. Der Rest ist nur where Klausel Logik:

select t.* 
from (select t.*, 
      max(case when action = 'donedeal' then date end) over 
       (partition by user, product order by date) as last_donedealdate 
     from t 
    ) t 
where action = 'new' and date < dateadd(day, 3, last_donedealdate); 
+0

Danke, dass Sie sich die Zeit genommen haben, auf meinen Beitrag zu antworten, sehr geschätzt. Eine Sache, die ich zurückgelassen habe, ist, dass der Typ nicht derselbe sein muss. Es mag in meinem Beispiel nicht klar sein, warum es wichtig ist, aber im wirklichen Leben ist es ein Problem. Ich habe versucht, Ihre Lösung zu ändern, aber die Ergebnisse waren nicht die gewünschten. Darf ich um weitere Hilfe bitten? :) – ct14

+0

@ ct14. . . Das macht es komplizierter. –

+0

Vielen Dank. Mit einer kleinen Änderung habe ich es zur Arbeit geschafft. Der Typ ist ein boolesches Feld (0 oder 1).Es gibt also nur 2 Szenarien für mich und ich replizierte den Code und die Verwendung von UNION ALL schloss sich den 2 Szenarien an. Zählt es als schlechter Übungscode? – ct14