sql >> Base de Datos >  >> RDS >> Oracle

Palabra clave Oracle 'Partition By' y 'Row_Number'

PARTITION BY conjuntos separados, esto le permite poder trabajar (ROW_NUMBER(), COUNT(), SUM(), etc.) en conjuntos relacionados de forma independiente.

En su consulta, el conjunto relacionado consta de filas con cdt.country_code, cdt.account, cdt.currency similares. Cuando realiza la partición en esas columnas y aplica ROW_NUMBER en ellas. Esas otras columnas en esa combinación/conjunto recibirán un número secuencial de ROW_NUMBER

Pero esa consulta es divertida, si su partición por algunos datos únicos y le pone un número de fila, simplemente producirá el mismo número. Es como si hicieras un ORDEN POR en una partición que está garantizada como única. Ejemplo, piense en GUID como una combinación única de cdt.country_code, cdt.account, cdt.currency

newid() produce GUID, entonces, ¿qué esperará de esta expresión?

select
   hi,ho,
   row_number() over(partition by newid() order by hi,ho)
from tbl;

... Correcto, todas las filas particionadas (ninguna fue particionada, cada fila está dividida en su propia fila) los números de fila de las filas están todos establecidos en 1

Básicamente, debe particionar en columnas no únicas. ORDER BY on OVER necesitaba que PARTITION BY tuviera una combinación no única; de lo contrario, todos los números de fila se convertirán en 1

Un ejemplo, estos son tus datos:

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');

Entonces esto es análogo a su consulta:

select
   hi,ho,
   row_number() over(partition by hi,ho order by hi,ho)
from tbl;

¿Cuál será el resultado de eso?

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

¿Ves la combinación de HI HO? Las primeras tres filas tienen una combinación única, por lo tanto, se establecen en 1, las filas B tienen la misma W, por lo tanto, ROW_NUMBERS diferentes, al igual que las filas HI C.

Ahora, ¿por qué ORDER BY se necesita ahi? Si el desarrollador anterior simplemente quiere poner un número de fila en datos similares (por ejemplo, HI B, todos los datos son B-W, B-W), puede hacer esto:

select
   hi,ho,
   row_number() over(partition by hi,ho)
from tbl;

Pero, por desgracia, Oracle (y Sql Server también) no permite la partición sin ORDER BY; mientras que en Postgresql, ORDER BY en PARTICIÓN es opcional:http://www.sqlfiddle.com/#!1/27821/1

select
   hi,ho,
   row_number() over(partition by hi,ho)
from tbl;

Tu ORDER BY en su partición parece un poco redundante, no por culpa del desarrollador anterior, algunas bases de datos simplemente no permiten PARTITION sin ORDER BY , es posible que no pueda encontrar una buena columna candidata para ordenar. Si las columnas PARTICIÓN POR y ORDEN POR son iguales, simplemente elimine ORDEN POR, pero como algunas bases de datos no lo permiten, puede hacer esto:

SELECT cdt.*,
        ROW_NUMBER ()
        OVER (PARTITION BY cdt.country_code, cdt.account, cdt.currency
              ORDER BY newid())
           seq_no
   FROM CUSTOMER_DETAILS cdt

¿No puede encontrar una buena columna para ordenar datos similares? También puede ordenar al azar, los datos particionados tienen los mismos valores de todas formas. Puede usar GUID por ejemplo (usa newid() para el servidor SQL). Entonces, tiene el mismo resultado realizado por el desarrollador anterior, es desafortunado que alguna base de datos no permita PARTITION sin ORDER BY

Aunque en realidad, se me escapa y no puedo encontrar una buena razón para poner un número en las mismas combinaciones (B-W, B-W en el ejemplo anterior). Da la impresión de que la base de datos tiene datos redundantes. De alguna manera me recordó esto:¿Cómo obtener un registro único de la misma lista de registros de la tabla? Sin restricción única en la tabla

Realmente parece extraño ver una PARTICIÓN POR con la misma combinación de columnas con ORDEN POR, no se puede inferir fácilmente la intención del código.

Prueba en vivo:http://www.sqlfiddle.com/#!3/27821/6

Pero como también ha notado dbaseman, es inútil particionar y ordenar en las mismas columnas.

Tienes un conjunto de datos 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');

Entonces usted PARTICIONA POR hola, ho; y luego ORDENA POR hi,ho. No tiene sentido numerar datos similares :-) 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;

Salida:

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 qué es necesario poner números de fila en la misma combinación? ¿Qué analizarás sobre triple A,X, sobre doble B,Y, sobre doble C,Z? :-)

Solo necesita usar PARTICIÓN en una columna no única, luego ordenar en columna(s) no única(s) único -ing columna. El ejemplo lo hará más 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 en una columna no única, luego en cada columna particionada, ordena en su columna única (ho), ORDER BY ho

Salida:

HI  HO  NR
A   D   1
A   E   2
A   F   3
B   E   1
B   F   2
C   D   1
C   E   2

Ese conjunto de datos tiene más sentido

Prueba en vivo:http://www.sqlfiddle.com/#!3/d0b44/1

Y esto es similar a su consulta con las mismas columnas en PARTICIÓN POR y ORDEN POR:

select
   hi,ho,
   row_number() over(partition by hi,ho order by hi,ho) as nr
from tbl;

Y esta es la salida:

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? no tiene sentido?

Prueba en vivo:http://www.sqlfiddle.com/#!3/d0b44/3

Finalmente, esta podría ser la consulta correcta:

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