2012-05-07 1 views
32

У меня есть SQL-запрос, написанный кем-то другим, и я пытаюсь понять, что он делает. Может кто-нибудь объяснить, что именно здесь делают слова Partition By и Row_Number, и дать простой пример этого в действии, а также почему он хотел бы использовать его?Ключевое слово Oracle 'Partition By' и 'Row_Number'

Пример раздела по:

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

Я видел несколько примеров в Интернете, они находятся в слишком глубине.

Заранее благодарен!

ответ

89

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; 

... Да, все разделы (ни один не был разбит на разделы, каждая строка разбивается в отдельной строке) row_numbers строк все готово к 1

В принципе, вы должны разделить на неуникальным колонны. ORDER BY на OVER необходимо ограждающей 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 

Вы видите thee комбинацию HI HO? Первые три строки имеют уникальную комбинацию, поэтому они установлены в 1, строки B имеют одинаковые W, а следовательно, разные ROW_NUMBERS, аналогично строкам HI C.

Теперь, зачем нужен ORDER BY? Если предыдущий разработчик просто хотите поставить row_number на аналогичные данные (например, HI B, все данные BW, BW), он может просто сделать это:

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

Хотя на самом деле, он ускользает от меня, и я не могу найти хороший повод, чтобы поставить номер на те же комбинации (BW, BW в примере выше). Это создает впечатление, что база данных имеет избыточные данные. Как-то напомнил мне об этом: How to get one unique record from the same list of records from table? No Unique constraint in the table

Это действительно выглядит тайным, видя 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'); 

Тогда вы PARTITION BY привет, хо; и тогда вы ЗАКАЗЫВАЕТ привет, хо. Там нет смысла нумерации подобные данные :-) 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 на неуникальном колонке, то сортировать по неуникальному колонку (ов) 's уникального -ный колонка.Пример сделает его более ясным:

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 работает на не уникальном столбце, а затем на каждую секционированную колонке, заказ на своей уникальной колонке (хо), 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; 

И это Ouput:

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 
7

Это выбирает номер строки для кода страны, счета и валюты. Таким образом, строки с кодом страны «США», счет «XYZ» и валютой «$ USD» будут каждый получить номер строки, присвоенный с 1-n; то же самое относится к любой другой комбинации этих столбцов в результирующем наборе.

Этот вопрос является забавным, потому что заказом от пункт ничего не делает. Все строки в каждом разделе имеют одинаковый код страны, учетную запись и валюту, поэтому эти столбцы не упорядочивают точки. Поэтому конечные номера строк, назначенные в этом конкретном запросе, будут непредсказуемыми.

Надежда, что помогает ...

4

Я часто использую row_number(), как быстрый способ отбросить повторяющиеся записи из моих отборных заявлений. Просто добавьте предложение where. Что-то вроде ...

select a,b,rn 
    from (select a, b, row_number() over (partition by a,b order by a,b) as rn   
      from table) 
where rn=1; 
2

Я знаю, что это старая нить, но PARTITION является эквивой GROUP BY не ORDER BY. ORDER BY в этой функции. , , СОРТИРОВАТЬ ПО. Это просто способ создать уникальность из избыточности, добавив порядковый номер. Или вы можете исключить другие избыточные записи по предложению WHERE, ссылаясь на столбцы с псевдонимом для функции. Однако DISTINCT в выражении SELECT, вероятно, выполнит то же самое в этом отношении.