Oracle“分区依据”关键字


253

有人可以解释一下partition by关键字的作用,并给出一个简单的示例,以及为什么要使用它吗?我有一个别人写的SQL查询,我试图弄清楚它的作用。

通过以下方式进行分区的示例:

SELECT empno, deptno, COUNT(*) 
OVER (PARTITION BY deptno) DEPT_COUNT
FROM emp

我在网上看到的示例似乎过于深入。


Answers:


259

PARTITION BY子句设置了该子句中每个“ GROUP”将使用的记录范围OVER

在您的示例SQL中,DEPT_COUNT将为每个员工记录返回该部门内的员工人数。(就好像您要对emp表进行非标称化;您仍然返回emp表中的每个记录。)

emp_no  dept_no  DEPT_COUNT
1       10       3
2       10       3
3       10       3 <- three because there are three "dept_no = 10" records
4       20       2
5       20       2 <- two because there are two "dept_no = 20" records

如果还有另一列(例如state),则可以计算该州的部门数。

这就像获取GROUP BYSUMAVG等)的结果而不汇总结果集(即删除匹配的记录)一样。

当您使用LAST OVERMIN OVER函数获取(例如)部门的最低和最高薪水,然后将其用于此记录薪水的计算中时,如果没有子选择,这将非常有用,这会更快。

阅读链接的AskTom文章以获取更多详细信息。


6
LAST_VALUE-返回上一个薪水,MAX返回最高薪水
Maciek Kreft

1
您的意思是“没有子选择,这要慢得多”?我想如果子选择比last over和慢或快,我会感到困惑min over。我以为子选择会比较慢,但是答案中的英语语法却没有建议。
杰森

这种方法减少了处理行的次数,从而使其比子选择更为有效。在非常大的数据集中最明显。
盖伊

164

公认的答案很好地解释了这个概念,但是我发现人们看到的例子越多,它的作用就越大。这是一个增量示例:

1)老板说 “让我按品牌分组的库存数量”

你说:“没问题”

SELECT 
      BRAND
      ,COUNT(ITEM_ID) 
FROM 
      ITEMS
GROUP BY 
      BRAND;

结果:

+--------------+---------------+
|  Brand       |   Count       | 
+--------------+---------------+
| H&M          |     50        |
+--------------+---------------+
| Hugo Boss    |     100       |
+--------------+---------------+
| No brand     |     22        |
+--------------+---------------+

2)老板说: “现在让我得到所有物品的清单,以及它们的品牌和相应品牌拥有的物品数量”

您可以尝试:

 SELECT 
      ITEM_NR
      ,BRAND
      ,COUNT(ITEM_ID) 
 FROM 
      ITEMS
 GROUP BY 
      BRAND;

但是你得到:

ORA-00979: not a GROUP BY expression 

这是OVER (PARTITION BY BRAND)进来的地方:

 SELECT 
      ITEM_NR
      ,BRAND
      ,COUNT(ITEM_ID) OVER (PARTITION BY BRAND) 
 FROM 
      ITEMS;

意思是:

  • COUNT(ITEM_ID) -获取项目数
  • OVER -在行集中
  • (PARTITION BY BRAND) -具有相同的品牌

结果是:

+--------------+---------------+----------+
|  Items       |  Brand        | Count()  |
+--------------+---------------+----------+
|  Item 1      |  Hugo Boss    |   100    | 
+--------------+---------------+----------+
|  Item 2      |  Hugo Boss    |   100    | 
+--------------+---------------+----------+
|  Item 3      |  No brand     |   22     | 
+--------------+---------------+----------+
|  Item 4      |  No brand     |   22     | 
+--------------+---------------+----------+
|  Item 5      |  H&M          |   50     | 
+--------------+---------------+----------+

等等...


3
如果我想每个小组都得到一个结果..我怎么得到它?
Viuu -a

您知道OVER PARTITION BY是否可以在WHERE子句中使用吗?
凯文·伯顿

我建议您就SO提出一个问题,提供具体信息并解释您要实现的目标
Andrejs

@ Viuu-a:那么您可能想要使用一个简单的GROUP BY。
jackthehipster

喜欢这个例子...易于理解
Johnny Wu

27

它是称为“分析”的SQL扩展。select语句中的“ over”告诉oracle该函数是分析函数,而不是按功能分组。使用分析的优势在于,您只需一次传递数据就可以收集总和,计数以及更多内容,而不是通过子选择或更糟糕的PL / SQL遍历数据。

乍一看确实令人困惑,但这很快就会成为第二天性。没有人比汤姆·凯特(Tom Kyte)解释得更好。因此,上面的链接很棒。

当然,必须阅读文档


9
EMPNO     DEPTNO DEPT_COUNT

 7839         10          4
 5555         10          4
 7934         10          4
 7782         10          4 --- 4 records in table for dept 10
 7902         20          4
 7566         20          4
 7876         20          4
 7369         20          4 --- 4 records in table for dept 20
 7900         30          6
 7844         30          6
 7654         30          6
 7521         30          6
 7499         30          6
 7698         30          6 --- 6 records in table for dept 30

在这里,我们正在获得各自的部门编号。至于deptno 10,我们在表emp中有4条记录,对于deptno 20和30也有类似的结果。


12
没有解释Partition by如何工作的问题。仅示例输出并不能完全回答问题。
Siraj Samsudeen

2

over partition关键字就像我们通过client_id创建数据分区一样,创建每个client id的子集

select client_id, operation_date,
       row_number() count(*) over (partition by client_id order by client_id ) as operationctrbyclient
from client_operations e
order by e.client_id;

该查询将返回由client_id完成的操作数


0

我认为,该示例暗示了分区工作方式和分组方式的细微差别。我的示例来自Oracle 12,如果我的示例恰巧是一个编译错误。

我试过了 :

SELECT t.data_key
,      SUM ( CASE when t.state = 'A' THEN 1 ELSE 0 END) 
OVER   (PARTITION BY t.data_key) count_a_rows
,      SUM ( CASE when t.state = 'B' THEN 1 ELSE 0 END) 
OVER   (PARTITION BY t.data_key) count_b_rows
,      SUM ( CASE when t.state = 'C' THEN 1 ELSE 0 END) 
OVER   (PARTITION BY t.data_key) count_c_rows
,      COUNT (1) total_rows
from mytable t
group by t.data_key  ---- This does not compile as the compiler feels that t.state isn't in the group by and doesn't recognize the aggregation I'm looking for

但是,这按预期工作:

SELECT distinct t.data_key
,      SUM ( CASE when t.state = 'A' THEN 1 ELSE 0 END) 
OVER   (PARTITION BY t.data_key) count_a_rows
,      SUM ( CASE when t.state = 'B' THEN 1 ELSE 0 END) 
OVER   (PARTITION BY t.data_key) count_b_rows
,      SUM ( CASE when t.state = 'C' THEN 1 ELSE 0 END) 
OVER   (PARTITION BY t.data_key) count_c_rows
,      COUNT (1) total_rows
from mytable t;

根据外部键“ data_key”产生每种状态下的元素数。因此,如果data_key ='APPLE'具有3行,其状态为'A',2行其状态为'B',一行具有状态'C',则'APPLE'的对应行将为'APPLE',3、2 ,1、6

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.