2016-06-02 4 views
2

Hatte eine kurze Suche online, um zu sehen, ob eine Antwort darauf bereits existierte. Konnte nichts finden, was diese besondere Situation ansprach (was eine Überraschung war, da ich angenommen hatte, dass es ziemlich häufig vorkam).SQL [Oracle]: Anzahl der vorherigen Datensätze mit derselben Client-ID zählen

Grundsätzlich habe ich eine Tabelle, die Registrierungen mit einem Dienst registriert, zusammen mit der ID der Client-Registrierung und das Start- und Enddatum der Registrierung. Siehe unten für ein Beispiel der Tabellenstruktur:

Reg ID | Client ID | Reg Start | Reg End 

R6  C1   01-06-2016 Null 
R5  C2   20-05-2016 02-06-2016 
R4  C2   14-03-2016 11-05-2016 
R3  C1   10-03-2016 05-05-2016 
R2  C2   28-01-2016 02-02-2016 
R1  C2   10-11-2015 23-12-2015 

Was ich tun möchte, ist es, die Datensätze aus der Tabelle ziehen, sondern auch eine Spalte hinzufügen, die eine Anzahl von zurückgibt, wie viele vorherige Anmeldungen sind in der Tabelle mit der gleiche Client-ID für jeden Datensatz. Aus Gründen der Übersichtlichkeit möchte ich nur Registrierungen für jeden Datensatz zählen, die dieselbe Kunden-ID haben und ein Startdatum haben, das kleiner als das des Datensatzes ist.

Als solche eine erfolgreiche Abfrage die folgende Ausgabe zurückkehren würde:

Reg ID | Client ID | Reg Start | Reg End | # previous reg 

R6  C1   01-06-2016 Null   1 
R5  C2   20-05-2016 02-06-2016 3 
R4  C2   14-03-2016 11-05-2016 2 
R3  C1   10-03-2016 05-05-2016 0 
R2  C2   28-01-2016 02-02-2016 1 
R1  C2   10-11-2015 23-12-2015 0 

Hat jemand schon Erfahrung, dies zu tun, die eine tragfähige Lösung bieten könnte?

Mein erster Gedanke war, eine Unterabfrage zu erstellen, die Registrierungen nach Client-ID gruppiert und dann diese mit meiner Hauptabfrage unter Verwendung der Client-ID verbindet. Zum Beispiel:

SELECT 
t1.reg_id 
t1.client_id 
t1.reg_start 
t1.reg_end 
FROM registrations t1 
JOIN 
    (SELECT 
    client_id 
    count(reg_id) 
    FROM registrations 
    GROUP BY client_id) t2 
ON t1.client_id = t2.client_id 

jedoch zurückkehren würde dies eine Zählung der Gesamt Registrierungen für einen bestimmten Client pro Datensatz, in dem, wie ich die vorherigen Anmeldungen speziell erfordern.

Jede Eingabe, die der Bienenstock Geist bieten könnte, würde sehr geschätzt werden. Ich denke, ich habe ein bisschen eine Wand mit meinem derzeit ziemlich begrenzten SQL-Wissen hier getroffen:/

Auch sollte ich wahrscheinlich erwähnen, dass ich eine Oracle-Datenbank verwende!

Antwort

2

Sie können dies mit row_number():

select r.*, 
     (row_number() over (partition by client_id order by reg_start) - 1) as cnt 
from registrations r; 
+0

Wäre es nicht besser, count (*) anstelle von row_number() zu verwenden? – vercelli

+1

@vercelli. . . Ich weiß nicht, dass einer "besser" ist als der andere. 'row_number()' ist traditioneller als 'count (*)' mit einer 'order by' Klausel. Darüber hinaus können die beiden etwas andere Dinge tun, wenn es doppelte Startdaten gibt. –

+0

Danke, das ist genau die Art von einfachen und eleganten Lösung, die ich suchte. Hat perfekt funktioniert. War vorher nicht von der Existenz von "Fenster" -Funktionen bewusst, aber jetzt, wo ich bin, kann ich bereits großes Potenzial für ihre Verwendung in anderen Bereichen sehen =) – RDG

1

In SQL Server Sie die folgende Abfrage verwenden:

SELECT [Reg ID], [Client ID], Reg_Start, Reg_End, 
     COUNT(*) OVER (PARTITION BY [Client ID] ORDER BY Reg_Start) - 1 
FROM mytable 

COUNT, wenn sie mit einer ORDER BY Klausel angewendet, gibt die insgesamt läuft Anzahl der Datensätze zählen. Wenn dies in Oracle verfügbar ist, sollte es den gewünschten Wert zurückgeben.

2

Dies kann mit einer Fensterfunktion und einer laufenden Summe erfolgen:

select reg_id, client_id, reg_start, reg_end, 
     count(*) over (partition by client_id order by reg_start) - 1 as previous_reg 
from registrations 
order by reg_start desc; 
0

Der einfachste Weg, meiner Meinung nach ist eine Unterabfrage in der SELECT Anweisung von Haupt-Abfrage zu erstellen, wie folgt:

SELECT 
    t1.*, 
    (
     SELECT COUNT(*) 
     FROM registrations t2 
     WHERE t2.client_id = t1.client_id 
      AND t2.reg_start < t1.reg_start 
    ) AS previous_reg 
FROM registrations t1 
ORDER BY reg_id DESC 
+0

Danke. Ich ging am Ende mit den anderen Vorschlägen, aber sehr nützlich, um zu sehen, dass es auch so gemacht werden kann. – RDG

+0

@RDG: Dieser Ansatz ist normalerweise viel langsamer als die Verwendung einer Fensterfunktion –

Verwandte Themen