Dit is gemakkelijk te doen met een techniek genaamd Tabibitosan.
Wat deze techniek doet, is de posities van de rijen van elke groep vergelijken met de totale reeks rijen, om te bepalen of rijen in dezelfde groep naast elkaar liggen of niet.
Met uw voorbeeldgegevens ziet dit er bijvoorbeeld als volgt uit:
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 heb ik alle rijen over de hele set gegevens een rijnummer gegeven in oplopende id-volgorde (de overall_rn
kolom), en ik heb de rijen in elke afdeling een rijnummer gegeven (de department_rn
kolom), opnieuw in oplopende ID-volgorde.
Nu ik dat heb gedaan, kunnen we de een van de ander aftrekken (de grp
kolom).
Merk op hoe het getal in de kolom grp hetzelfde blijft voor naast elkaar gelegen afdelingsrijen, maar het verandert elke keer dat er een opening is.
bijv. voor de afdeling Marketing liggen de rijen 1-3 naast elkaar en hebben grp =0, maar de 4e rij Marketing staat eigenlijk op de 5e rij van de totale resultatenset, dus deze heeft nu een ander grp-nummer. Aangezien de 5e marketingrij zich op de 6e rij van de totale set bevindt, heeft deze hetzelfde grp-nummer als de 4e marketingrij, dus we weten dat ze naast elkaar staan.
Zodra we die grp-informatie hebben, is het een kwestie van een geaggregeerde querygroepering op zowel de afdeling als onze nieuwe grp-kolom, met min en max om de begin- en eind-id's te vinden:
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
N.B., ik ben ervan uitgegaan dat gaten in de id-kolommen niet belangrijk zijn (d.w.z. als er geen rij was voor id =6 (dus Leo en Kevin's id's waren respectievelijk 7 en 8), dan zouden Leo en Brad nog steeds in dezelfde groep, met een start-id =5 en eind-id =7.
Als hiaten in de id-kolommen tellen als aanduiding van een nieuwe groep, kunt u de id gewoon gebruiken om de algemene reeks rijen te labelen (d.w.z. u hoeft de overall_rn niet te berekenen; gebruik in plaats daarvan gewoon de id-kolom).
Dat betekent dat uw vraag zou worden:
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