Oracle'Partition By'和'Row_Number'关键字

Has*_*imR 43 sql oracle row-number analytic-functions partition

我有一个由其他人编写的SQL查询,我正在试图找出它的作用.有人可以解释这里Partition ByRow_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 BYPARTITION是可选的: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).因此,具有由以前的开发取得了相同的输出,这是不幸的是,某些数据库不允许PARTITIONORDER 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)


McG*_*gle 7

这将选择每个国家/地区代码,帐户和货币的行号.因此,具有国家代码"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)