Has*_*imR 43 sql oracle row-number analytic-functions partition
我有一个由其他人编写的SQL查询,我正在试图找出它的作用.有人可以解释这里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);
Run Code Online (Sandbox Code Playgroud)
我在网上看过一些例子,它们有点太深入了.
提前致谢!
Mic*_*uen 100
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;
Run Code Online (Sandbox Code Playgroud)
...对,所有分区(没有分区,每行都在自己的行中分区)行'row_numbers都设置为1
基本上,您应该在非唯一列上进行分区.ORDER BY on 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');
Run Code Online (Sandbox Code Playgroud)
那么这类似于你的查询:
select
hi,ho,
row_number() over(partition by hi,ho order by hi,ho)
from tbl;
Run Code Online (Sandbox Code Playgroud)
那将是什么输出?
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
Run Code Online (Sandbox Code Playgroud)
你看到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;
Run Code Online (Sandbox Code Playgroud)
但是,唉,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;
Run Code Online (Sandbox Code Playgroud)
你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
Run Code Online (Sandbox Code Playgroud)
您找不到用于排序类似数据的好列?您也可以随机排序,分区数据无论如何都具有相同的值.例如,您可以使用GUID(您newid()
用于SQL Server).因此,具有由以前的开发取得了相同的输出,这是不幸的是,某些数据库不允许PARTITION
无ORDER BY
虽然真的,它让我望而却步,我找不到一个很好的理由把数字放在相同的组合上(BW,BW在上面的例子中).它给人的印象是数据库有冗余数据.以某种方式提醒我:如何从表中的同一记录列表中获取一个唯一记录?表中没有唯一约束
看到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');
Run Code Online (Sandbox Code Playgroud)
然后你分开喜,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;
Run Code Online (Sandbox Code Playgroud)
输出:
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
Run Code Online (Sandbox Code Playgroud)
看到?为什么需要将行号放在同一组合上?你将在双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;
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
该数据集更有意义
现场测试: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;
Run Code Online (Sandbox Code Playgroud)
这是输出:
HI HO NR
A D 1
A E 1
A F 1
B E 1
B F 1
C D 1
C E 1
Run Code Online (Sandbox Code Playgroud)
看到?没有意义?
现场测试: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
Run Code Online (Sandbox Code Playgroud)
这将选择每个国家/地区代码,帐户和货币的行号.因此,具有国家代码"US",帐户"XYZ"和货币"$ USD"的行将分别获得从1-n分配的行号; 结果集中这些列的每个其他组合也是如此.
这个查询很有趣,因为order by子句绝对没有任何意义.每个分区中的所有行都具有相同的国家/地区代码,帐户和货币,因此这些列没有任何排序顺序.因此,在此特定查询中分配的最终行号将是不可预测的.
希望有帮助......
小智 7
我经常使用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;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
261264 次 |
最近记录: |