Dies ist mit einer Technik namens Tabibitosan einfach zu bewerkstelligen.
Diese Technik vergleicht die Positionen der Zeilen jeder Gruppe mit dem Gesamtsatz von Zeilen, um herauszufinden, ob Zeilen in derselben Gruppe nebeneinander liegen oder nicht.
Mit Ihren Beispieldaten sieht das z. B. so aus:
WITH your_table AS (SELECT 1 ID, 'Michael' NAME, 'Marketing' department FROM dual UNION ALL
SELECT 2 ID, 'Alex' NAME, 'Marketing' department FROM dual UNION ALL
SELECT 3 ID, 'Tom' NAME, 'Marketing' department FROM dual UNION ALL
SELECT 4 ID, 'John' NAME, 'Sales' department FROM dual UNION ALL
SELECT 5 ID, 'Brad' NAME, 'Marketing' department FROM dual UNION ALL
SELECT 6 ID, 'Leo' NAME, 'Marketing' department FROM dual UNION ALL
SELECT 7 ID, 'Kevin' NAME, 'Production' department FROM dual)
-- end of mimicking your table with data in it. See the SQL below:
SELECT ID,
NAME,
department,
row_number() OVER (ORDER BY ID) overall_rn,
row_number() OVER (PARTITION BY department ORDER BY ID) department_rn,
row_number() OVER (ORDER BY ID) - row_number() OVER (PARTITION BY department ORDER BY ID) grp
FROM your_table;
ID NAME DEPARTMENT OVERALL_RN DEPARTMENT_RN GRP
---------- ------- ---------- ---------- ------------- ----------
1 Michael Marketing 1 1 0
2 Alex Marketing 2 2 0
3 Tom Marketing 3 3 0
4 John Sales 4 1 3
5 Brad Marketing 5 4 1
6 Leo Marketing 6 5 1
7 Kevin Production 7 1 6
Hier habe ich allen Zeilen über den gesamten Datensatz eine Zeilennummer in aufsteigender ID-Reihenfolge gegeben (die overall_rn
Spalte), und ich habe den Zeilen in jeder Abteilung eine Zeilennummer gegeben (die department_rn
Spalte), wieder in aufsteigender ID-Reihenfolge.
Jetzt, wo ich das getan habe, können wir einen vom anderen subtrahieren (die grp
Spalte).
Beachten Sie, dass die Zahl in der Spalte grp für nebeneinander liegende Abteilungszeilen gleich bleibt, sich aber bei jeder Lücke ändert.
Z.B. Für die Marketingabteilung liegen die Zeilen 1-3 nebeneinander und haben grp =0, aber die 4. Marketingzeile befindet sich tatsächlich in der 5. Zeile des Gesamtergebnissatzes und hat jetzt eine andere grp-Nummer. Da sich die 5. Marketingreihe in der 6. Reihe des Gesamtsatzes befindet, hat sie dieselbe Grp-Nummer wie die 4. Marketingreihe, sodass wir wissen, dass sie nebeneinander liegen.
Sobald wir diese grp-Informationen haben, ist es einfach, eine aggregierte Abfragegruppierung sowohl für die Abteilung als auch für unsere neue grp-Spalte durchzuführen, wobei min und max verwendet werden, um die Start- und End-IDs zu finden:
WITH your_table AS (SELECT 1 ID, 'Michael' NAME, 'Marketing' department FROM dual UNION ALL
SELECT 2 ID, 'Alex' NAME, 'Marketing' department FROM dual UNION ALL
SELECT 3 ID, 'Tom' NAME, 'Marketing' department FROM dual UNION ALL
SELECT 4 ID, 'John' NAME, 'Sales' department FROM dual UNION ALL
SELECT 5 ID, 'Brad' NAME, 'Marketing' department FROM dual UNION ALL
SELECT 6 ID, 'Leo' NAME, 'Marketing' department FROM dual UNION ALL
SELECT 7 ID, 'Kevin' NAME, 'Production' department FROM dual)
-- end of mimicking your table with data in it. See the SQL below:
SELECT department,
MIN(ID) start_id,
MAX(ID) end_id
FROM (SELECT ID,
NAME,
department,
row_number() OVER (ORDER BY ID) - row_number() OVER (PARTITION BY department ORDER BY ID) grp
FROM your_table)
GROUP BY department, grp;
DEPARTMENT START_ID END_ID
---------- ---------- ----------
Marketing 1 3
Marketing 5 6
Sales 4 4
Production 7 7
Hinweis:Ich bin davon ausgegangen, dass Lücken in den ID-Spalten nicht wichtig sind (d. H. Wenn es keine Zeile für ID =6 gäbe (die IDs von Leo und Kevin waren also 7 bzw. 8), würden Leo und Brad immer noch in der selben erscheinen Gruppe, mit einer Start-ID =5 und End-ID =7.
Wenn Lücken in den id-Spalten als Hinweis auf eine neue Gruppe zählen, könnten Sie einfach die id verwenden, um den gesamten Satz von Zeilen zu kennzeichnen (d. h. es ist nicht erforderlich, den Gesamt_rn zu berechnen; verwenden Sie stattdessen einfach die id-Spalte).
Das bedeutet, dass Ihre Abfrage folgendermaßen aussehen würde:
WITH your_table AS (SELECT 1 ID, 'Michael' NAME, 'Marketing' department FROM dual UNION ALL
SELECT 2 ID, 'Alex' NAME, 'Marketing' department FROM dual UNION ALL
SELECT 3 ID, 'Tom' NAME, 'Marketing' department FROM dual UNION ALL
SELECT 4 ID, 'John' NAME, 'Sales' department FROM dual UNION ALL
SELECT 5 ID, 'Brad' NAME, 'Marketing' department FROM dual UNION ALL
SELECT 7 ID, 'Leo' NAME, 'Marketing' department FROM dual UNION ALL
SELECT 8 ID, 'Kevin' NAME, 'Production' department FROM dual)
-- end of mimicking your table with data in it. See the SQL below:
SELECT department,
MIN(ID) start_id,
MAX(ID) end_id
FROM (SELECT ID,
NAME,
department,
ID - row_number() OVER (PARTITION BY department ORDER BY ID) grp
FROM your_table)
GROUP BY department, grp;
DEPARTMENT START_ID END_ID
---------- ---------- ----------
Marketing 1 3
Sales 4 4
Marketing 5 5
Marketing 7 7
Production 8 8