sql >> Databasteknik >  >> RDS >> Oracle

Oracle SQL - Identifiera sekventiella värdeintervall

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


  1. SQLite Connection läckte även om allt stängdes

  2. Återställning av SQL Server 2017

  3. Din ultimata guide till SQL Joins:OUTER JOIN – Del 2

  4. Hur man genererar DDL-skript (Skapa) från SQL Server Management Studio (SSMS) - SQL Server / TSQL Tutorial Del 17