Oracle
 sql >> база данни >  >> RDS >> Oracle

Oracle 'Partition By' и 'Row_Number' ключова дума

PARTITION BY отделни набори, това ви позволява да можете да работите (ROW_NUMBER(),COUNT(),SUM() и т.н.) върху свързан набор независимо.

Във вашата заявка свързаният набор се състои от редове с подобни cdt.country_code, cdt.account, cdt.currency. Когато разделите на тези колони и приложите ROW_NUMBER върху тях. Тези други колони в тази комбинация/набор ще получат пореден номер от ROW_NUMBER

Но тази заявка е смешна, ако вашият дял е с някакви уникални данни и поставите row_number върху него, то просто ще произведе същото число. Все едно правиш ORDER BY на дял, който гарантирано е уникален. Например, помислете за GUID като уникална комбинация от cdt.country_code, cdt.account, cdt.currency

newid() произвежда GUID, така че какво да очаквате от този израз?

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

...Добре, всички разделени (нито един не е бил разделен, всеки ред е разделен на собствен ред) номерата на редове на редове са всички настроени на 1

По принцип трябва да разделите на неуникални колони. ORDER BY на OVER се нуждаеше от PARTITION BY да има неуникална комбинация, в противен случай всички row_numbers ще станат 1

Пример, това са вашите данни:

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

Тогава това е аналогично на вашата заявка:

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

Какъв ще бъде резултатът от това?

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

Виждате ли комбинацията от HI HO? Първите три реда имат уникална комбинация, следователно те са зададени на 1, B редовете имат същия W, следователно различни ROW_NUMBERS, по същия начин с HI C редове.

Сега, защо е ORDER BY има нужда там? Ако предишният разработчик просто иска да постави row_number на подобни данни (например HI B, всички данни са B-W, B-W), той може просто да направи това:

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

Но уви, Oracle (и Sql Server също) не позволява дял без ORDER BY; докато в Postgresql, ORDER BY на PARTITION е по избор:http://www.sqlfiddle.com/#!1/27821/1

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

Вашият ORDER BY на вашия дял изглежда малко излишен, не поради грешка на предишния разработчик, някои бази данни просто не позволяват PARTITION без ORDER BY , той може да не успее да намери добър кандидат колона, по която да сортира. Ако и двете колони PARTITION BY и ORDER BY са еднакви, просто премахнете ORDER BY, но тъй като някои бази данни не го позволяват, можете просто да направите това:

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

Не можете да намерите добра колона, която да използвате за сортиране на подобни данни? Можете също да сортирате на случаен принцип, разделените данни имат същите стойности така или иначе. Можете да използвате GUID например (използвате newid() за SQL Server). Така че това има същия изход, направен от предишния разработчик, жалко е, че някои бази данни не позволяват PARTITION без ORDER BY

Въпреки че наистина, това ми убягва и не мога да намеря добра причина да сложа число на едни и същи комбинации (B-W, B-W в примера по-горе). Създава впечатление, че базата данни има излишни данни. Някак си ми напомни за това:Как да получа един уникален запис от същия списък със записи от таблица? Няма уникално ограничение в таблицата

Наистина изглежда тайнствено да видите PARTITION BY със същата комбинация от колони с ORDER BY, не може лесно да се заключи намерението на кода.

Тест на живо:http://www.sqlfiddle.com/#!3/27821/6

Но както dbaseman също забеляза, безполезно е да се разделят и подреждат на едни и същи колони.

Имате набор от данни като този:

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

Тогава вие РАЗДЕЛЯТЕ ОТ hi,ho; и след това ПОРЪЧВАТЕ ОТ hi,ho. Няма смисъл да номерирате подобни данни :-) 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;

Изход:

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

Виждаш ли? Защо трябва да поставяте номера на редове в една и съща комбинация? Какво ще анализирате на тройно A,X, на двойно B,Y, на двойно C,Z? :-)

Просто трябва да използвате PARTITION върху неуникална колона, след което сортирате по уникалната колона(и) на неуникална(и) -ing колона. Примерът ще направи по-ясно:

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 работи с неуникална колона, след което за всяка разделена колона, вие поръчвате по нейната уникална колона(ho), ORDER BY ho

Изход:

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

Този набор от данни има повече смисъл

Тест на живо:http://www.sqlfiddle.com/#!3/d0b44/1

И това е подобно на вашата заявка със същите колони както на PARTITION BY, така и на ORDER BY:

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

И това е изходът:

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

Виждаш ли? няма смисъл?

Тест на живо:http://www.sqlfiddle.com/#!3/d0b44/3

Най-накрая това може да е правилната заявка:

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Групово събиране и изпълнение незабавно в Oracle

  2. Пример за автономна транзакция на Oracle

  3. Пейджиране с Oracle

  4. COLLATION() Функция в Oracle

  5. Разбиране на Java на Oracle на Mac