sql >> Database teknologi >  >> RDS >> Oracle

Oracle 'Partition By' og 'Row_Number' nøgleord

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


  1. mysql_num_rows() forventer, at parameter 1 er ressource, boolesk givet ind

  2. Sådan rettes "EXECUTE-sætningen mislykkedes, fordi dens WITH RESULT SETS-klausul specificerede 2 kolonne(r) for resultatsæt..." Meddelelse 11537 i SQL Server

  3. MariaDB og Docker use cases, del 1

  4. Oracle Wait-begivenheder, som alle bør kende