PARTITION BY
segregerade uppsättningar, detta gör att du kan arbeta (ROW_NUMBER(),COUNT(),SUM(),etc) på relaterad uppsättning oberoende.
I din fråga består den relaterade uppsättningen av rader med liknande cdt.country_code, cdt.account, cdt.currency. När du partitionerar på dessa kolumner och du använder ROW_NUMBER på dem. De andra kolumnerna i den kombinationen/uppsättningen kommer att få sekvensnummer från ROW_NUMBER
Men den frågan är rolig, om din partitionering av några unika data och du lägger ett radnummer på den, kommer den bara att producera samma nummer. Det är som att du gör en ORDER BY på en partition som garanterat är unik. Tänk till exempel på GUID som en unik kombination av cdt.country_code, cdt.account, cdt.currency
newid()
producerar GUID, så vad kan du förvänta dig av detta uttryck?
select
hi,ho,
row_number() over(partition by newid() order by hi,ho)
from tbl;
...Höger, alla partitionerade (ingen var partitionerad, varje rad är partitionerad i sin egen rad) radernas radnummer är alla inställda på 1
I grund och botten bör du partitionera på icke-unika kolumner. ORDER BY on OVER behövde PARTITION BY för att ha en icke-unik kombination, annars blir alla radnummer 1
Ett exempel, detta är dina uppgifter:
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');
Då är detta analogt med din fråga:
select
hi,ho,
row_number() over(partition by hi,ho order by hi,ho)
from tbl;
Vad blir resultatet av 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 av HI HO? De första tre raderna har en unik kombination, därför är de inställda på 1, B-raderna har samma W, därav olika ROW_NUMBERS, likaså med HI C-rader.
Varför är ORDER BY
behövs där? Om den tidigare utvecklaren bara vill sätta ett radnummer på liknande data (t.ex. HI B, all data är B-W, B-W), kan han bara göra så här:
select
hi,ho,
row_number() over(partition by hi,ho)
from tbl;
Men tyvärr, Oracle (och SQL Server också) tillåter inte partitionering utan ORDER BY
; medan i Postgresql, ORDER BY
on PARTITION är valfritt: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 lite överflödig ut, inte på grund av den tidigare utvecklarens fel, vissa databas tillåter bara inte PARTITION
utan ORDER BY
, kanske han inte kan hitta en bra kandidatkolumn att sortera på. Om både PARTITION BY-kolumnerna och ORDER BY-kolumnerna är samma, ta bara bort ORDER BY, men eftersom en viss databas inte tillåter det, kan du bara göra så här:
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 inte hitta en bra kolumn att använda för att sortera liknande data? Du kan lika gärna sortera slumpmässigt, de partitionerade data har samma värden i alla fall. Du kan använda GUID till exempel (du använder newid()
för SQL Server). Så det har samma utdata från tidigare utvecklare, det är olyckligt att en del databas inte tillåter PARTITION
utan ORDER BY
Fast egentligen undviker det mig och jag kan inte hitta en bra anledning att sätta en siffra på samma kombinationer (B-W, B-W i exemplet ovan). Det ger intryck av att databasen har överflödiga data. På något sätt påminde mig om detta:Hur får man en unik post från samma lista med poster från tabellen? Ingen unik begränsning i tabellen
Det ser verkligen hemskt ut att se en PARTITION BY med samma kombination av kolumner med ORDER BY, kan inte lätt sluta sig till kodens avsikt.
Livetest:http://www.sqlfiddle.com/#!3/27821/6
Men som dbaseman också har märkt är det meningslöst att partitionera och beställa i samma kolumner.
Du har en uppsättning data så här:
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');
Då DELAR du AV hi,ho; och så BESTÄLLER du MED hej, ho. Det är ingen mening att numrera liknande 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;
Utdata:
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
Ser? Varför behöver du sätta radnummer på samma kombination? Vad ska du analysera på trippel A,X, på dubbel B,Y, på dubbel C,Z? :-)
Du behöver bara använda PARTITION på icke-unik kolumn, sedan sorterar du på icke-unika kolumners unika -ing kolumn. Exempel kommer att göra det mer tydligt:
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
fungerar på icke-unik kolumn, sedan på varje partitionerad kolumn beställer du på dess unika kolumn(ho), ORDER BY ho
Utdata:
HI HO NR
A D 1
A E 2
A F 3
B E 1
B F 2
C D 1
C E 2
Den datamängden är mer vettig
Livetest:http://www.sqlfiddle.com/#!3/d0b44/1
Och detta liknar din fråga med samma kolumner på både PARTITION BY och ORDER BY:
select
hi,ho,
row_number() over(partition by hi,ho order by hi,ho) as nr
from tbl;
Och det här är resultatet:
HI HO NR
A D 1
A E 1
A F 1
B E 1
B F 1
C D 1
C E 1
Ser? ingen mening?
Livetest:http://www.sqlfiddle.com/#!3/d0b44/3
Slutligen kan detta vara rätt fråga:
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