Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Palavra-chave Oracle 'Partition By' e 'Row_Number'


PARTITION BY conjuntos segregados, isso permite que você possa trabalhar (ROW_NUMBER(),COUNT(),SUM(),etc) no conjunto relacionado de forma independente.

Em sua consulta, o conjunto relacionado é composto por linhas com cdt.country_code, cdt.account, cdt.currency semelhantes. Quando você particiona nessas colunas e aplica ROW_NUMBER nelas. Essas outras colunas nessas combinações/conjuntos receberão o número sequencial de ROW_NUMBER

Mas essa consulta é engraçada, se sua partição por alguns dados exclusivos e você colocar um número_linha nela, ela produzirá o mesmo número. É como se você fizesse um ORDER BY em uma partição que é garantida como única. Exemplo, pense no GUID como uma combinação exclusiva de cdt.country_code, cdt.account, cdt.currency

newid() produz GUID, então o que você deve esperar por essa expressão?
select
   hi,ho,
   row_number() over(partition by newid() order by hi,ho)
from tbl;

...Certo, todos os números particionados (nenhum foi particionado, cada linha é particionada em sua própria linha) row_numbers estão todos definidos como 1

Basicamente, você deve particionar em colunas não exclusivas. ORDER BY em OVER precisava que PARTITION BY tivesse uma combinação não única, caso contrário, todos os row_numbers se tornarão 1

Um exemplo, estes são seus dados:
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');

Então isso é análogo à sua consulta:
select
   hi,ho,
   row_number() over(partition by hi,ho order by hi,ho)
from tbl;

Qual será a saída disso?
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

Você vê a combinação de HI HO? As três primeiras linhas têm uma combinação única, portanto, são definidas como 1, as linhas B têm o mesmo W, portanto ROW_NUMBERS diferentes, da mesma forma com as linhas HI C.

Agora, por que o ORDER BY precisava lá? Se o desenvolvedor anterior quiser apenas colocar um row_number em dados semelhantes (por exemplo, HI B, todos os dados são B-W, B-W), ele pode fazer isso:
select
   hi,ho,
   row_number() over(partition by hi,ho)
from tbl;

Mas, infelizmente, Oracle (e Sql Server também) não permite partição sem ORDER BY; enquanto no Postgresql, ORDER BY em PARTITION é opcional:http://www.sqlfiddle.com/#!1/27821/1
select
   hi,ho,
   row_number() over(partition by hi,ho)
from tbl;

Seu ORDER BY em sua partição parece um pouco redundante, não por culpa do desenvolvedor anterior, alguns bancos de dados simplesmente não permitem PARTITION sem ORDER BY , ele pode não encontrar uma boa coluna candidata para classificar. Se ambas as colunas PARTITION BY e ORDER BY forem iguais, basta remover o ORDER BY, mas como alguns bancos de dados não permitem, você pode fazer isso:
SELECT cdt.*,
        ROW_NUMBER ()
        OVER (PARTITION BY cdt.country_code, cdt.account, cdt.currency
              ORDER BY newid())
           seq_no
   FROM CUSTOMER_DETAILS cdt

Você não consegue encontrar uma boa coluna para usar para classificar dados semelhantes? Você também pode classificar aleatoriamente, os dados particionados têm os mesmos valores qualquer maneira. Você pode usar o GUID por exemplo (você usa newid() para SQL Server). Para que tenha a mesma saída feita pelo desenvolvedor anterior, é lamentável que algum banco de dados não permita PARTITION sem ORDER BY

Embora, na verdade, isso me escapa e não consigo encontrar uma boa razão para colocar um número nas mesmas combinações (B-W, B-W no exemplo acima). Está dando a impressão de banco de dados com dados redundantes. De alguma forma me lembrou disso:Como obter um registro exclusivo da mesma lista de registros da tabela? Nenhuma restrição exclusiva na tabela

Realmente parece arcano ver um PARTITION BY com a mesma combinação de colunas com ORDER BY, não dá para inferir facilmente a intenção do código.

Teste ao vivo:http://www.sqlfiddle.com/#!3/27821/6

Mas como o dbaseman também notou, é inútil particionar e ordenar nas mesmas colunas.

Você tem um conjunto de dados como este:
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');

Então você PARTITION BY hi,ho; e então você PEDE BY oi, ho. Não faz sentido numerar dados semelhantes :-) 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;

Saída:
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

Ver? Por que precisa colocar números de linha na mesma combinação? O que você vai analisar no triplo A,X, no duplo B,Y, no duplo C,Z? :-)

Você só precisa usar PARTITION na coluna não-única e, em seguida, classifica na(s) coluna(s) não-única(s) únicas coluna -ing. O exemplo deixará mais claro:
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 opera em coluna não exclusiva, então em cada coluna particionada, você ordena em sua coluna exclusiva (ho), ORDER BY ho

Saída:
HI  HO  NR
A   D   1
A   E   2
A   F   3
B   E   1
B   F   2
C   D   1
C   E   2

Esse conjunto de dados faz mais sentido

Teste ao vivo:http://www.sqlfiddle.com/#!3/d0b44/1

E isso é semelhante à sua consulta com as mesmas colunas em PARTITION BY e ORDER BY:
select
   hi,ho,
   row_number() over(partition by hi,ho order by hi,ho) as nr
from tbl;

E esta é a saída:
HI  HO  NR
A   D   1
A   E   1
A   F   1
B   E   1
B   F   1
C   D   1
C   E   1

Ver? nenhum sentido?

Teste ao vivo:http://www.sqlfiddle.com/#!3/d0b44/3

Finalmente, esta pode ser a consulta certa:
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