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