Oracle“分区依据”和“Row_Number”关键字

jjjwad0x  于 2022-12-22  发布在  Oracle
关注(0)|答案(4)|浏览(167)

我有一个由其他人编写的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);
ippsafx7

ippsafx71#

PARTITION BY隔离集合,这使您能够独立地处理相关集合(ROW_NUMBER()、COUNT()、SUM()等)。
In your query, the related set comprised of rows with similar cdt.country_code, cdt.account, cdt.currency. When you partition on those columns and you apply ROW_NUMBER on them. Those other columns on those combination/set will receive sequential number from ROW_NUMBER
但是这个查询很有趣,如果你用一些唯一的数据进行分区,并且你在它上面放了一个row_number,它只会产生相同的数字。这就像你在一个保证是唯一的分区上做了一个ORDER BY。
newid()产生GUID,那么这个表达式应该有什么作用呢?

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

...对,所有分区的行(没有分区,每行都在自己的行中分区)的row_numbers都设置为1
基本上,您应该对非唯一列进行分区。OVER上的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,所有数据都是B-W,B-W),他可以这样做:

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

但是遗憾的是,Oracle(和Sql Server)不允许没有ORDER BY的分区;而在Postgresql中,PARTITION上的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作为例子(你使用newid() for SQL Server)。所以这与以前的开发人员所做的输出相同,不幸的是,一些数据库不允许PARTITION没有ORDER BY
虽然真的,它逃避我,我找不到一个很好的理由把一个数字在相同的组合(B-W,B-W在上面的例子)。它给人的印象数据库有冗余数据。不知何故提醒我这一点:How to get one unique record from the same list of records from table? No Unique constraint in the table
它真的看起来很神秘,看到一个分区与相同的列组合与顺序,不能轻易推断代码的意图。
实时测试: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');

然后你被嗨,嗬;然后你ORDER BY 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,然后在非唯一列的 * unique *-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
1aaf6o9v

1aaf6o9v2#

我经常使用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;
k4ymrczo

k4ymrczo3#

它选择每个国家代码、账户和货币的行号,因此,国家代码为“US”、账户为“XYZ”、货币为“$USD”的行将分别获得从1到n分配的行号;这同样适用于结果集中那些列的每一个其它组合。
这个查询很有趣,因为order by子句什么都不做,每个分区中的所有行都有相同的国家代码、帐户和货币,所以没有按这些列排序的点,因此在这个特定查询中分配的最终行号是不可预测的。
希望能有所帮助...

fnatzsnv

fnatzsnv4#

我知道这是一个旧的线程,但是PARTITION等同于GROUP BY而不是ORDER BY。在这个函数中ORDER BY是... ORDER BY。它只是一种通过添加序列号从冗余中创建唯一性的方法。或者,您可以在引用函数的别名列时通过WHERE子句消除其他冗余记录。但是,在这方面,SELECT语句中的DISTINCT可能会完成同样的任务。

相关问题