Това е лесно да се направи с техника, наречена Табибитозан.
Това, което прави тази техника, е да сравнява позициите на редовете на всяка група с общия набор от редове, за да разберете дали редовете в същата група са един до друг или не.
Например с вашите примерни данни това изглежда така:
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
Тук съм дал на всички редове в целия набор от данни номер на ред във възходящ ред на идентификатора (overall_rn
колона) и дадох на редовете във всеки отдел номер на ред (department_rn
колона), отново във възходящ ред на идентификатора.
След като направих това, можем да извадим едното от другото (grp
колона).
Забележете как числото в колоната grp остава същото за редовете на отделите, които са един до друг, но се променя всеки път, когато има празнина.
напр. за отдел „Маркетинг“, редове 1-3 са един до друг и имат grp =0, но 4-тият маркетингов ред всъщност е на 5-ия ред от общия набор от резултати, така че вече има различен gp номер. Тъй като 5-ият маркетингов ред е на 6-ия ред от общия набор, той има същият номер на групата като 4-ия маркетингов ред, така че знаем, че са един до друг.
След като имаме тази grp информация, е лесно да направим обобщено групиране на заявки както за отдела, така и за нашата нова колона grp, като използваме min и max за намиране на началния и крайния идентификатор:
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., предположих, че пропуските в колоните за идентификатор не са важни (т.е. ако нямаше ред за id =6 (така че идентификаторите на Лео и Кевин бяха съответно 7 и 8), тогава Лео и Брад все още биха се появявали в същото група, с начален идентификатор =5 и краен идентификатор =7.
Ако пропуските в колоните с идентификатор се считат за посочване на нова група, тогава можете просто да използвате идентификатора за етикетиране на общия набор от редове (т.е. няма нужда да изчислявате total_rn; просто използвайте колоната с идентификатор вместо това).
Това означава, че вашата заявка ще бъде:
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