PARTITION BY
adskilte sæt, dette giver dig mulighed for at arbejde (ROW_NUMBER(),COUNT(),SUM(),osv) på relateret sæt uafhængigt.
I din forespørgsel består det relaterede sæt af rækker med lignende cdt.country_code, cdt.account, cdt.currency. Når du partitionerer på disse kolonner, og du anvender ROW_NUMBER på dem. De andre kolonner på disse kombinationer/sæt vil modtage fortløbende nummer fra ROW_NUMBER
Men den forespørgsel er sjov, hvis din partition med nogle unikke data, og du sætter et row_number på det, vil det bare producere det samme nummer. Det er som om du laver en ORDER BY på en partition, der med garanti er unik. For eksempel, tænk på GUID som en unik kombination af cdt.country_code, cdt.account, cdt.currency
newid()
producerer GUID, så hvad kan du forvente af dette udtryk?
select
hi,ho,
row_number() over(partition by newid() order by hi,ho)
from tbl;
...Til højre, alle de partitionerede (ingen var opdelt, hver række er opdelt i deres egen række) rækkernes række_numre er alle sat til 1
Grundlæggende bør du partitionere på ikke-unikke kolonner. ORDER BY på OVER havde brug for PARTITION BY for at have en ikke-unik kombination, ellers bliver alle row_numbers 1
Et eksempel, dette er dine 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');
Så er dette analogt med din forespørgsel:
select
hi,ho,
row_number() over(partition by hi,ho order by hi,ho)
from tbl;
Hvad bliver resultatet af det?
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
Ser du en kombination af HI HO? De første tre rækker har en unik kombination, derfor er de sat til 1, B-rækkerne har samme W, derfor forskellige ROW_NUMBERS, ligeledes med HI C-rækker.
Hvorfor er ORDER BY
brug for der? Hvis den tidligere udvikler blot ønsker at sætte et rækkenummer på lignende data (f.eks. HI B, alle data er B-W, B-W), kan han bare gøre dette:
select
hi,ho,
row_number() over(partition by hi,ho)
from tbl;
Men desværre tillader Oracle (og også SQL Server) ikke partition uden ORDER BY
; hvorimod i Postgresql, ORDER BY
on PARTITION er valgfrit:http://www.sqlfiddle.com/#!1/27821/1
select
hi,ho,
row_number() over(partition by hi,ho)
from tbl;
Din ORDER BY
på din partition ser lidt overflødig ud, ikke på grund af den tidligere udviklers fejl, nogle databaser tillader bare ikke PARTITION
uden ORDER BY
, kan han måske ikke finde en god kandidatkolonne at sortere efter. Hvis både PARTITION BY-kolonner og ORDER BY-kolonner er de samme, skal du bare fjerne ORDER BY, men da nogle databaser ikke tillader det, kan du bare gøre dette:
SELECT cdt.*,
ROW_NUMBER ()
OVER (PARTITION BY cdt.country_code, cdt.account, cdt.currency
ORDER BY newid())
seq_no
FROM CUSTOMER_DETAILS cdt
Du kan ikke finde en god kolonne til at bruge til at sortere lignende data? Du kan lige så godt sortere tilfældigt, de opdelte data har de samme værdier alligevel. Du kan f.eks. bruge GUID (du bruger newid()
til SQL Server). Så det har det samme output lavet af tidligere udvikler, det er uheldigt, at nogle databaser ikke tillader PARTITION
uden ORDER BY
Selvom det virkelig undslipper mig, og jeg kan ikke finde en god grund til at sætte et tal på de samme kombinationer (B-W, B-W i eksemplet ovenfor). Det giver indtryk af, at databasen har overflødige data. På en eller anden måde mindede mig om dette:Hvordan får man en unik post fra den samme liste over poster fra tabellen? Ingen unik begrænsning i tabellen
Det ser virkelig mystisk ud at se en PARTITION BY med samme kombination af kolonner med ORDER BY, kan ikke nemt udlede kodens hensigt.
Live test:http://www.sqlfiddle.com/#!3/27821/6
Men som dbaseman også har bemærket, er det nytteløst at opdele og bestille på samme kolonner.
Du har et sæt data som dette:
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');
Så DELER du VED hi,ho; og så BESTILLER I AF hej, ho. Der er ingen mening at nummerere lignende data :-) 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;
Output:
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
Se? Hvorfor skal du sætte rækkenumre på samme kombination? Hvad vil du analysere på triple A,X, på dobbelt B,Y, på dobbelt C,Z? :-)
Du skal bare bruge PARTITION på ikke-unik kolonne, så sorterer du på ikke-unikke kolonne(r)s unikke -ing kolonne. Eksempel vil gøre det mere klart:
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
opererer på ikke-entydig kolonne, derefter bestiller du på hver opdelt kolonne på dens unikke kolonne(ho), ORDER BY ho
Output:
HI HO NR
A D 1
A E 2
A F 3
B E 1
B F 2
C D 1
C E 2
Det datasæt giver mere mening
Live test:http://www.sqlfiddle.com/#!3/d0b44/1
Og dette svarer til din forespørgsel med samme kolonner på både PARTITION BY og ORDER BY:
select
hi,ho,
row_number() over(partition by hi,ho order by hi,ho) as nr
from tbl;
Og dette er outputtet:
HI HO NR
A D 1
A E 1
A F 1
B E 1
B F 1
C D 1
C E 1
Se? ingen mening?
Live test:http://www.sqlfiddle.com/#!3/d0b44/3
Endelig kan dette være den rigtige forespørgsel:
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