Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Oracle SQL — Zidentyfikuj kolejne zakresy wartości

Jest to łatwe dzięki technice zwanej Tabibitosan.

Ta technika polega na porównaniu pozycji wierszy każdej grupy z całym zestawem wierszy, aby sprawdzić, czy wiersze w tej samej grupie są obok siebie, czy nie.

Np. z przykładowymi danymi wygląda to tak:

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

Tutaj nadałem wszystkim wierszom w całym zestawie danych numer wiersza w rosnącej kolejności identyfikatorów (overall_rn kolumna) i nadałem wierszom w każdym dziale numer wiersza (department_rn kolumna), ponownie w rosnącej kolejności identyfikatorów.

Teraz, gdy to zrobiłem, możemy odjąć jedno od drugiego (grp kolumna).

Zwróć uwagę, że liczba w kolumnie grp pozostaje taka sama dla wierszy oddziałów znajdujących się obok siebie, ale zmienia się za każdym razem, gdy pojawia się luka.

Np. w przypadku działu marketingu wiersze 1-3 znajdują się obok siebie i mają grp =0, ale czwarty wiersz marketingu znajduje się w rzeczywistości w piątym wierszu ogólnego zestawu wyników, więc ma teraz inny numer grp. Ponieważ piąty wiersz marketingowy znajduje się w szóstym rzędzie całego zestawu, ma ten sam numer grupy, co czwarty wiersz marketingowy, więc wiemy, że są one obok siebie.

Gdy mamy już te informacje grp, wystarczy wykonać grupowanie zagregowanych zapytań zarówno w dziale, jak i w naszej nowej kolumnie grp, używając min i max do znalezienia identyfikatorów początkowych i końcowych:

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

Uwaga, założyłem, że luki w kolumnach id nie są ważne (tzn. gdyby nie było wiersza dla id =6 (więc id Leo i Kevina wynosiły odpowiednio 7 i 8), to Leo i Brad nadal pojawiliby się w tym samym grupa, z identyfikatorem początkowym =5 i identyfikatorem końcowym =7.

Jeśli przerwy w kolumnach id liczą się jako wskazujące na nową grupę, możesz po prostu użyć tego identyfikatora do oznaczenia całego zestawu wierszy (tzn. nie trzeba obliczać ogólnego_rn; zamiast tego użyj kolumny id).

Oznacza to, że Twoje zapytanie wyglądałoby następująco:

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. ORACLE — Wybierz opcję Policz w podzapytaniu

  2. Oracle SQL:Użyj sekwencji we wstawce z instrukcją Select

  3. Generuj dane testowe za pomocą programisty Oracle PL/SQL

  4. Jak poprawnie korzystać z Oracle ORDER BY i ROWNUM?

  5. Korzystanie z usług heterogenicznych Oracle® z dwoma źródłami danych ODBC