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

Klíčové slovo Oracle 'Partition By' a 'Row_Number'

PARTITION BY segregovat sady, to vám umožní pracovat (ROW_NUMBER(),COUNT(),SUM(),atd.) na související sadě nezávisle.

Ve vašem dotazu související sada složená z řádků s podobným kódem cdt.country_code, cdt.account, cdt.currency. Když na těchto sloupcích vytvoříte oddíly a použijete na ně ROW_NUMBER. Tyto ostatní sloupce v této kombinaci/sadě obdrží pořadové číslo od ROW_NUMBER

Ale ten dotaz je legrační, pokud váš oddíl obsahuje nějaká jedinečná data a vložíte na něj row_number, vytvoří to stejné číslo. Je to jako byste provedli ORDER BY na oddílu, který je zaručeně jedinečný. Představte si například GUID jako jedinečnou kombinaci cdt.country_code, cdt.account, cdt.currency

newid() vytváří GUID, takže co můžete od tohoto výrazu očekávat?

select
   hi,ho,
   row_number() over(partition by newid() order by hi,ho)
from tbl;

...Správně, u všech rozdělených (žádný nebyl rozdělen, každý řádek je rozdělen na svůj vlastní řádek) řádky row_numbers jsou všechny nastaveny na 1

V zásadě byste měli rozdělovat na nejedinečné sloupce. ORDER BY on OVER potřeboval, aby PARTITION BY měla nejedinečnou kombinaci, jinak budou všechna čísla row_numbers 1

Příkladem jsou vaše data:

create table tbl(hi varchar, ho varchar);

insert into tbl values
('A','X'),
('A','Y'),
('A','Z'),
('B','W'),
('B','W'),
('C','L'),
('C','L');

Pak je to analogické s vaším dotazem:

select
   hi,ho,
   row_number() over(partition by hi,ho order by hi,ho)
from tbl;

Jaký z toho bude výstup?

HI  HO  COLUMN_2
A   X   1
A   Y   1
A   Z   1
B   W   1
B   W   2
C   L   1
C   L   2

Vidíš tu kombinaci HI HO? První tři řádky mají jedinečnou kombinaci, proto jsou nastaveny na 1, řádky B mají stejné W, tedy různé ROW_NUMBERS, stejně jako řádky HI C.

Nyní, proč je ORDER BY potřeba tam? Pokud chce předchozí vývojář pouze umístit row_number na podobná data (např. HI B, všechna data jsou B-W, B-W), může to udělat takto:

select
   hi,ho,
   row_number() over(partition by hi,ho)
from tbl;

Ale bohužel, Oracle (a také SQL Server) nepovoluje oddíl bez ORDER BY; zatímco v Postgresql ORDER BY na PARTITION je volitelný:http://www.sqlfiddle.com/#!1/27821/1

select
   hi,ho,
   row_number() over(partition by hi,ho)
from tbl;

Vaše ORDER BY na vašem oddílu vypadají trochu nadbytečně, ne kvůli chybě předchozího vývojáře, některé databáze prostě neumožňují PARTITION bez ORDER BY , nemusí být schopen najít sloupec vhodného kandidáta, podle kterého by se dal třídit. Pokud jsou oba sloupce PARTITION BY a ORDER BY stejné, odeberte ORDER BY, ale protože to některé databáze neumožňují, můžete to udělat takto:

SELECT cdt.*,
        ROW_NUMBER ()
        OVER (PARTITION BY cdt.country_code, cdt.account, cdt.currency
              ORDER BY newid())
           seq_no
   FROM CUSTOMER_DETAILS cdt

Nemůžete najít dobrý sloupec pro třídění podobných dat? Můžete také třídit náhodně, data rozdělená na oddíly mají stejné hodnoty tak jako tak. Můžete použít například GUID (použijete newid() pro SQL Server). Takže to má stejný výstup vytvořený předchozím vývojářem, je nešťastné, že některá databáze neumožňuje PARTITION bez ORDER BY

I když ve skutečnosti mi to uniká a nemůžu najít dobrý důvod, abych dal číslo na stejné kombinace (B-W, B-W v příkladu výše). Vyvolává to dojem, že databáze má nadbytečná data. Nějak mi to připomnělo:Jak získat jeden unikátní záznam ze stejného seznamu záznamů z tabulky? Žádné jedinečné omezení v tabulce

Opravdu to vypadá tajemně, když vidíme PARTITION BY se stejnou kombinací sloupců s ORDER BY, nelze snadno odvodit záměr kódu.

Živý test:http://www.sqlfiddle.com/#!3/27821/6

Ale jak si také dbaseman všiml, je zbytečné rozdělovat a objednávat ve stejných sloupcích.

Máte sadu dat, jako je tato:

create table tbl(hi varchar, ho varchar);

insert into tbl values
('A','X'),
('A','X'),
('A','X'),
('B','Y'),
('B','Y'),
('C','Z'),
('C','Z');

Pak rozdělíte hi,ho; a pak si OBJEDNÁVEJTE hi,ho. Podobná data nemá smysl číslovat :-) http://www.sqlfiddle.com/#!3/29ab8/3

select
   hi,ho,
   row_number() over(partition by hi,ho order by hi,ho) as nr
from tbl;

Výstup:

HI  HO  ROW_QUERY_A
A   X   1
A   X   2
A   X   3
B   Y   1
B   Y   2
C   Z   1
C   Z   2

Vidět? Proč je potřeba vkládat čísla řádků do stejné kombinace? Co budete analyzovat na trojitém A,X, na dvojitém B,Y, na dvojitém C,Z? :-)

Stačí použít PARTITION pro nejedinečný sloupec a poté seřadit podle unikátních sloupců, které nejsou jedinečné -ing sloupec. Příklad to objasní:

create table tbl(hi varchar, ho varchar);

insert into tbl values
('A','D'),
('A','E'),
('A','F'),
('B','F'),
('B','E'),
('C','E'),
('C','D');

select
   hi,ho,
   row_number() over(partition by hi order by ho) as nr
from tbl;

PARTITION BY hi funguje na nejedinečném sloupci, pak na každém rozděleném sloupci objednáváte podle jeho jedinečného sloupce (ho), ORDER BY ho

Výstup:

HI  HO  NR
A   D   1
A   E   2
A   F   3
B   E   1
B   F   2
C   D   1
C   E   2

Tento soubor dat dává větší smysl

Živý test:http://www.sqlfiddle.com/#!3/d0b44/1

A toto je podobné vašemu dotazu se stejnými sloupci na PARTITION BY a ORDER BY:

select
   hi,ho,
   row_number() over(partition by hi,ho order by hi,ho) as nr
from tbl;

A toto je výstup:

HI  HO  NR
A   D   1
A   E   1
A   F   1
B   E   1
B   F   1
C   D   1
C   E   1

Vidět? nemá smysl?

Živý test:http://www.sqlfiddle.com/#!3/d0b44/3

Konečně by to mohl být správný dotaz:

SELECT cdt.*,
     ROW_NUMBER ()
     OVER (PARTITION BY cdt.country_code, cdt.account -- removed: cdt.currency
           ORDER BY 
               -- removed: cdt.country_code, cdt.account, 
               cdt.currency) -- keep
        seq_no
FROM CUSTOMER_DETAILS cdt


  1. Typ data bez času v Oracle

  2. SQLite NOT NULL omezení

  3. Použití SSH tunelování jako alternativy VPN

  4. Jak poznám id před uložením objektu do jpa