Detta är lätt att göra med en teknik som kallas Tabibitosan.
Vad den här tekniken gör är att jämföra positionerna för varje grupps rader med den totala uppsättningen av rader, för att ta reda på om raderna i samma grupp ligger bredvid varandra eller inte.
Med din exempeldata ser det till exempel ut så här:
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
Här har jag gett alla rader över hela datauppsättningen ett radnummer i stigande id-ordning (overall_rn
kolumn), och jag har gett raderna i varje avdelning ett radnummer (department_rn
kolumn), igen i stigande id-ordning.
Nu när jag har gjort det kan vi subtrahera det ena från det andra (grp
kolumn).
Lägg märke till hur numret i grp-kolumnen förblir detsamma för avdelningsrader som ligger bredvid varandra, men det ändras varje gång det finns ett gap.
T.ex. för marknadsföringsavdelningen ligger raderna 1-3 bredvid varandra och har grp =0, men den fjärde marknadsföringsraden är faktiskt på den femte raden i den totala resultatuppsättningen, så den har nu ett annat grp-nummer. Eftersom den 5:e marknadsföringsraden är på den 6:e raden i den totala uppsättningen har den samma grp-nummer som den fjärde marknadsföringsraden, så vi vet att de ligger bredvid varandra.
När vi väl har den grp-informationen är det en enkel fråga att göra en sammanställd frågegruppering på både avdelningen och vår nya grp-kolumn, använda min och max för att hitta start- och slut-ID:t:
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
OBS, jag har antagit att luckor i id-kolumnerna inte är viktiga (dvs. om det inte fanns någon rad för id =6 (så Leo och Kevins id var 7 respektive 8), så skulle Leo och Brad fortfarande visas i samma grupp, med start-id =5 och slut-id =7.
Om luckor i id-kolumnerna räknas som att indikera en ny grupp, kan du helt enkelt använda id:t för att märka den övergripande uppsättningen rader (dvs. du behöver inte beräkna total_rn, använd bara id-kolumnen istället).
Det betyder att din fråga blir:
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