2012-05-07 84 views
32

我有一個由其他人編寫的SQL查詢,我試圖找出它的作用。有人可以解釋關鍵字Partition ByRow_Number在這裏的作用,並給出一個簡單的例子,以及爲什麼要使用它?Oracle'分區依據'和'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超過所需的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,所有的數據都BW,BW),他只是這樣做:

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

但很可惜,甲骨文(和SQL Server太)沒有按不允許分區沒有ORDER BY;而在PostgreSQL,ORDER BY上分區是可選的: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(對SQL Server使用newid())。因此,具有由以前的開發取得了相同的輸出,這是不幸的是,某些數據庫不允許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'); 

然後你分區中喜,豪;然後你訂購嗨,嗨。毫無意義的編號類似的數據:-) 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? :-)


你只需要在非唯一列中使用分區,那麼您排序非唯一列(S)的獨特 -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 
7

選擇每個國家代碼,帳戶和貨幣的行號。因此,國家代碼爲「US」,帳戶「XYZ」和貨幣「$ USD」的行將分別獲得從1-n分配的行號;結果集中這些列的每個其他組合都是一樣的。

這個查詢很有趣,因爲order by子句絕對沒有。每個分區中的所有行都具有相同的國家/地區代碼,帳戶和貨幣,因此這些列沒有排序順序。因此,在此特定查詢中分配的最終行號將無法預測。

希望幫助...

4

我經常使用ROW_NUMBER()作爲一個快速的方法來從我的select語句丟棄重複的記錄。只需添加一個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在這個函數中。 。 。 ORDER BY。這只是一種通過添加序列號來創造冗餘的獨特性的方法。或者,當引用該函數的別名列時,您可以通過WHERE子句消除其他冗餘記錄。但是,SELECT語句中的DISTINCT在這方面可能會完成同樣的事情。