sql >> Database teknologi >  >> RDS >> Oracle

Oracle SQL - Identificer sekventielle værdiområder

Dette er nemt at gøre med en teknik kaldet Tabibitosan.

Hvad denne teknik gør, er at sammenligne positionerne af hver gruppes rækker med det samlede sæt af rækker for at finde ud af, om rækker i samme gruppe er ved siden af ​​hinanden eller ej.

Med dine eksempeldata ser dette f.eks. sådan ud:

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

Her har jeg givet alle rækkerne på tværs af hele datasættet et rækkenummer i stigende id-rækkefølge (overall_rn kolonne), og jeg har givet rækkerne i hver afdeling et rækkenummer (department_rn kolonne), igen i stigende id-rækkefølge.

Nu hvor jeg har gjort det, kan vi trække det ene fra det andet (grp kolonne).

Bemærk, hvordan tallet i grp-kolonnen forbliver det samme for afdelingsrækker, der er ved siden af ​​hinanden, men det ændrer sig, hver gang der er et hul.

For eksempel. for marketingafdelingen ligger række 1-3 ved siden af ​​hinanden og har grp =0, men 4. marketingrække er faktisk på 5. række i det samlede resultatsæt, så den har nu et andet grp-nummer. Da 5. marketingrække er på 6. række i det samlede sæt, har den samme grp-nummer som 4. marketingrække, så vi ved, at de er ved siden af ​​hinanden.

Når vi først har disse grp-oplysninger, er det et simpelt spørgsmål om at lave en samlet forespørgselsgruppering på både afdelingen og vores nye grp-kolonne, ved at bruge min og max til at finde start- og slut-id'erne:

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., jeg har antaget, at huller i id-kolonnerne ikke er vigtige (dvs. hvis der ikke var nogen række for id =6 (så Leo og Kevins id var henholdsvis 7 og 8), så ville Leo og Brad stadig optræde i det samme gruppe, med et start-id =5 og slut-id =7.

Hvis huller i id-kolonnerne tæller som at angive en ny gruppe, så kan du bare bruge id'et til at mærke det overordnede sæt af rækker (dvs. det er ikke nødvendigt at beregne overall_rn; brug blot id-kolonnen i stedet).

Det betyder, at din forespørgsel bliver:

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. World Backup Day:4 interessante datatabsfakta at vide

  2. SQL Server Join Estimation ved hjælp af Histogram Coarse Alignment

  3. formater interval med to_char

  4. CONNECT BY eller hierarkiske forespørgsler i andre RDBMS end Oracle