คีย์เวิร์ด Oracle“ Partition By”


253

ใครช่วยกรุณาอธิบายว่าpartition byคำหลักทำอะไรได้บ้างและยกตัวอย่างง่ายๆของการใช้คำหลักนี้รวมถึงสาเหตุที่ใครต้องการใช้มัน ฉันมีแบบสอบถาม SQL ที่เขียนโดยคนอื่นและฉันพยายามคิดว่ามันทำอะไร

ตัวอย่างของพาร์ติชันโดย:

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

ตัวอย่างที่ฉันได้เห็นทางออนไลน์นั้นค่อนข้างละเอียดเกินไป


ลิงก์อื่นที่เกี่ยวข้อง: postgresql.org/docs/9.1/static/tutorial-window.html
Shashank Vivek

คำตอบ:


259

PARTITION BYข้อกำหนดช่วงของระเบียนที่จะใช้สำหรับแต่ละ "กลุ่ม บริษัท" ภายใน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 BY( SUM, AVGฯลฯ ) โดยไม่รวมชุดผลลัพธ์ (เช่นลบบันทึกที่ตรงกัน)

มันจะมีประโยชน์เมื่อคุณใช้LAST OVERหรือMIN OVERฟังก์ชั่นที่จะได้รับเช่นเงินเดือนต่ำสุดและสูงที่สุดในแผนกแล้วใช้มันในการคำนวณกับเงินเดือนบันทึกนี้โดยไม่ต้องเลือกย่อยซึ่งเร็วกว่ามาก

อ่านบทความ AskTom ที่เชื่อมโยงเพื่อดูรายละเอียดเพิ่มเติม


6
LAST_VALUE - ส่งคืนเงินเดือนล่าสุด MAX ส่งคืนเงินเดือนสูงสุด
Maciek Kreft

1
คุณหมายถึง "ไม่มีตัวเลือกย่อยซึ่งช้ากว่านี้มาก" ผมคิดว่าผมกำลังสับสนถ้าย่อยเลือกจะช้าหรือเร็วกว่าและlast over min overฉันนึกภาพตัวเลือกย่อยจะช้ากว่า แต่ไวยากรณ์ภาษาอังกฤษในคำตอบไม่ได้แนะนำสิ่งนั้น
Jason

วิธีการนี้จะลดจำนวนครั้งที่แถวประมวลผลทำให้มีประสิทธิภาพมากกว่าการเลือกย่อย ส่วนใหญ่ที่เห็นได้ชัดเจนในชุดข้อมูลที่มีขนาดใหญ่มาก
Guy

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 clause ได้บ้าง?
เควินเบอร์ตัน

ฉันขอแนะนำให้คุณถามคำถามเกี่ยวกับ SO ให้เจาะจงและอธิบายสิ่งที่คุณต้องการบรรลุ
Andrejs

@ Viuu-a: ถ้าอย่างนั้นคุณอาจจะต้องการใช้ GROUP แบบง่าย ๆ
jackthehipster

รักตัวอย่างนี้ ... เข้าใจง่าย
Johnny Wu

27

มันเป็นนามสกุล SQL ที่เรียกว่าการวิเคราะห์ คำว่า "over" ในคำสั่ง select บอก 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 ตามลำดับ สำหรับ deptno 10 เรามี 4 บันทึกในตาราง EMP ผลลัพธ์ที่คล้ายคลึงกันสำหรับ deptno 20 และ 30 เช่นกัน


12
ไม่มีการตีความคำถามว่า PARTITION ทำงานอย่างไร ตัวอย่างผลลัพธ์เพียงอย่างเดียวไม่สามารถตอบคำถามได้อย่างเต็มที่
Siraj Samsudeen

2

คำหลักของพาร์ทิชันที่มากกว่าคือถ้าเรากำลังแบ่งพาร์ติชันข้อมูลโดยการสร้าง 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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.