sql >> Databáze >  >> RDS >> Oracle

Oracle SQL – Identifikujte sekvenční rozsahy hodnot

To je snadné udělat pomocí techniky zvané Tabibitosan.

Tato technika umožňuje porovnat pozice řádků každé skupiny s celkovou sadou řádků, aby se zjistilo, zda jsou řádky ve stejné skupině vedle sebe nebo ne.

Například s vašimi vzorovými daty to vypadá takto:

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

Zde jsem všem řádkům v celé sadě dat přiřadil číslo řádku ve vzestupném pořadí id (overall_rn sloupec) a řádkům v každém oddělení jsem přidělil číslo řádku (department_rn sloupec), opět ve vzestupném pořadí id.

Nyní, když jsem to udělal, můžeme odečíst jeden od druhého (grp sloupec).

Všimněte si, že číslo ve sloupci grp zůstává stejné pro řádky oddělení, které jsou vedle sebe, ale mění se pokaždé, když je mezera.

Např. pro marketingové oddělení jsou řádky 1-3 vedle sebe a mají grp =0, ale 4. řádek marketingu je ve skutečnosti na 5. řádku celkové sady výsledků, takže má nyní jiné číslo grp. Vzhledem k tomu, že 5. marketingová řada je na 6. řadě celé sady, má stejné grp číslo jako 4. marketingová řada, takže víme, že jsou vedle sebe.

Jakmile budeme mít informace o skupině grp, je to jednoduchá záležitost seskupení agregovaných dotazů na oddělení i náš nový sloupec skupiny grp pomocí min a max k nalezení počátečního a koncového ID:

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

POZN., předpokládal jsem, že mezery ve sloupcích id nejsou důležité (tj. pokud tam nebyl žádný řádek pro id =6 (takže Leo a Kevinovo id bylo 7 a 8), pak by se Leo a Brad stále objevovali ve stejném skupina s počátečním id =5 a koncovým id =7.

Pokud se mezery ve sloupcích id počítají jako označení nové skupiny, můžete k označení celé sady řádků použít pouze id (tj. není třeba počítat celkový_rn, stačí místo toho použít sloupec id).

To znamená, že váš dotaz bude:

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. MyISAM versus InnoDB

  2. Jak získat aktuální datum (bez času) v T-SQL

  3. fe_sendauth:nebylo zadáno žádné heslo

  4. Vystoupení SUBSTR na CLOB