Điều này rất dễ thực hiện với một kỹ thuật có tên là Tabibitosan.
Những gì kỹ thuật này thực hiện là so sánh vị trí của các hàng trong nhóm với tập hợp các hàng tổng thể, để tìm ra liệu các hàng trong cùng một nhóm có cạnh nhau hay không.
Ví dụ:với dữ liệu mẫu của bạn, nó trông giống như sau:
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
Ở đây, tôi đã cung cấp cho tất cả các hàng trên toàn bộ tập dữ liệu một số hàng theo thứ tự id tăng dần (overall_rn
), và tôi đã cung cấp cho các hàng trong mỗi bộ phận một số hàng (department_rn
cột), lại theo thứ tự id tăng dần.
Bây giờ tôi đã làm điều đó, chúng ta có thể trừ một cái cho cái kia (grp
cột).
Lưu ý rằng số trong cột grp vẫn giữ nguyên như thế nào đối với các hàng mô tả cạnh nhau, nhưng nó thay đổi mỗi khi có khoảng trống.
Ví dụ. đối với bộ phận Tiếp thị, hàng 1-3 nằm cạnh nhau và có grp =0, nhưng hàng Tiếp thị thứ 4 thực sự nằm trên hàng thứ 5 của tập kết quả tổng thể, vì vậy nó hiện có số grp khác. Vì hàng tiếp thị thứ 5 nằm trên hàng thứ 6 của tập hợp tổng thể, nó có cùng số grp với hàng tiếp thị thứ 4, vì vậy chúng tôi biết chúng ở cạnh nhau.
Khi chúng tôi có thông tin grp đó, việc đơn giản là thực hiện nhóm truy vấn tổng hợp trên cả bộ phận và cột grp mới của chúng tôi, sử dụng min và max để tìm id đầu và cuối:
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., tôi đã cho rằng khoảng trống trong các cột id không quan trọng (tức là nếu không có hàng nào cho id =6 (vì vậy id của Leo và Kevin lần lượt là 7 và 8), thì Leo và Brad sẽ vẫn xuất hiện trong cùng một nhóm, với id bắt đầu =5 và id kết thúc =7.
Nếu khoảng trống trong các cột id được coi là biểu thị một nhóm mới, thì bạn chỉ có thể sử dụng id để gắn nhãn cho tập hợp các hàng tổng thể (tức là không cần tính tổng thể_rn; chỉ cần sử dụng cột id thay thế).
Điều đó có nghĩa là truy vấn của bạn sẽ trở thành:
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