SQL Server: ความแตกต่างระหว่าง PARTITION BY และ GROUP BY


365

ฉันใช้GROUP BYคำค้นหารวมทุกประเภทในช่วงหลายปีที่ผ่านมา เมื่อเร็ว ๆ นี้ฉันได้วิศวกรรมย้อนกลับบางรหัสที่ใช้PARTITION BYในการรวมตัว ในการอ่านเอกสารทั้งหมดที่ฉันสามารถหาได้PARTITION BYมันฟังดูเหมือนมากGROUP BYบางทีอาจมีฟังก์ชั่นพิเศษเพิ่มเติมเล็กน้อยบ้างไหม? พวกเขามีฟังก์ชั่นทั่วไปสองรุ่นที่เหมือนกันหรือว่าเป็นสิ่งที่แตกต่างอย่างสิ้นเชิง?

คำตอบ:


440

พวกมันถูกใช้ในสถานที่ต่างกัน group byแก้ไขข้อความค้นหาทั้งหมดเช่น:

select customerId, count(*) as orderCount
from Orders
group by customerId

แต่ใช้partition byงานได้ในฟังก์ชั่นหน้าต่างเช่นrow_number:

select row_number() over (partition by customerId order by orderId)
    as OrderNumberForThisCustomer
from Orders

group byปกติจะช่วยลดจำนวนของแถวกลับโดยกลิ้งพวกเขาและการคำนวณค่าเฉลี่ยหรือเงินก้อนสำหรับแต่ละแถว partition byไม่ส่งผลกระทบต่อจำนวนแถวที่ส่งคืน แต่เปลี่ยนแปลงวิธีการคำนวณผลลัพธ์ของฟังก์ชันหน้าต่าง


23
คำตอบที่ดีคุณช่วยกรุณาเขียนตัวอย่างของผลลัพธ์ที่ส่งกลับสำหรับแต่ละของพวกเขา?
Ashkan Mobayen Khiabani

2
@AshkanMobayenKhiabani คุณสามารถเรียกใช้ข้อความค้นหาทั้งสองกับ Northwind ซึ่งอาจจะติดตั้งหรือไม่ก็ได้ขึ้นอยู่กับรุ่นของ sql server ของคุณ ถ้าไม่คุณสามารถค้นหาได้ในหน้าดาวน์โหลด
Fetchez la vache

15
@AshkanMobayenKhiabani คำตอบของ Arunprasanth ด้านล่างแสดงผลลัพธ์ที่ได้กลับคืนซึ่งช่วยให้คุณประหยัดเวลาได้มากกว่าการกระโดดผ่านห่วงการเรียนรู้และเวลาในการเรียนรู้ Northwind มากขึ้น
Praxiteles

1
เพิ่มเติมเกี่ยวกับฟังก์ชั่นของ windows (ใน SQL): blog.jooq.org/2013/11/03/…
datps

itcodehub.blogspot.com/2019/03/ … - ข้อมูลเพิ่มเติมและตัวอย่างเกี่ยวกับความแตกต่างระหว่างกลุ่มโดยและพาร์ติชันโดยใน sql
xproph

252

เราสามารถนำตัวอย่างง่ายๆ

พิจารณาตารางที่ตั้งชื่อTableAด้วยค่าต่อไปนี้:

id  firstname                   lastname                    Mark
-------------------------------------------------------------------
1   arun                        prasanth                    40
2   ann                         antony                      45
3   sruthy                      abc                         41
6   new                         abc                         47
1   arun                        prasanth                    45
1   arun                        prasanth                    49
2   ann                         antony                      49

GROUP BY

ส่วนคำสั่ง SQL GROUP BY สามารถใช้ในคำสั่ง SELECT เพื่อรวบรวมข้อมูลจากหลาย ๆ ระเบียนและจัดกลุ่มผลลัพธ์ตามคอลัมน์อย่างน้อยหนึ่งคอลัมน์

ในคำที่ง่ายขึ้นคำสั่ง GROUP BY ถูกใช้ร่วมกับฟังก์ชั่นรวมเพื่อจัดกลุ่มผลลัพธ์ที่กำหนดโดยหนึ่งหรือมากกว่าหนึ่งคอลัมน์

ไวยากรณ์:

SELECT expression1, expression2, ... expression_n, 
       aggregate_function (aggregate_expression)
FROM tables
WHERE conditions
GROUP BY expression1, expression2, ... expression_n;

เราสามารถใช้GROUP BYในตารางของเรา:

select SUM(Mark)marksum,firstname from TableA
group by id,firstName

ผล:

marksum  firstname
----------------
94      ann                      
134     arun                     
47      new                      
41      sruthy   

ในตารางจริงของเราเรามี 7 แถวและเมื่อเรานำไปใช้GROUP BY idเซิร์ฟเวอร์จะจัดกลุ่มผลลัพธ์ตามid:

ในคำง่าย ๆ :

GROUP BYตามปกติแล้วที่นี่จะช่วยลดจำนวนแถวที่คืนกลับมาโดยการเลื่อนและคำนวณSum()สำหรับแต่ละแถว

PARTITION BY

ก่อนที่จะไปที่พาร์ทิชันโดยให้เราดูOVERข้อ:

ตามคำจำกัดความของ MSDN:

ข้อ OVER กำหนดหน้าต่างหรือชุดของแถวที่ผู้ใช้ระบุภายในชุดผลลัพธ์แบบสอบถาม ฟังก์ชั่นหน้าต่างจะคำนวณค่าสำหรับแต่ละแถวในหน้าต่าง คุณสามารถใช้ OVER clause กับฟังก์ชั่นเพื่อคำนวณค่าที่สรุปรวมเช่นค่าเฉลี่ยเคลื่อนที่, ผลรวมสะสม, ผลรวมสะสมหรือจำนวน N สูงสุดต่อผลลัพธ์กลุ่ม

PARTITION BY จะไม่ลดจำนวนแถวที่ส่งคืน

เราสามารถใช้ PARTITION โดยในตารางตัวอย่างของเรา:

SELECT SUM(Mark) OVER (PARTITION BY id) AS marksum, firstname FROM TableA

ผลลัพธ์:

marksum firstname 
-------------------
134     arun                     
134     arun                     
134     arun                     
94      ann                      
94      ann                      
41      sruthy                   
47      new  

ดูผลลัพธ์ - มันจะแบ่งแถวและส่งคืนแถวทั้งหมดไม่เหมือน GROUP BY


3
partition by สามารถส่งผลกระทบต่อจำนวนแถวเพียง แต่จะไม่ลดจำนวนแถว
จอห์น

1
จะเกิดอะไรขึ้นถ้าฉันเปลี่ยนSELECTเป็น SELECT DISTINCTคิวรีที่สอง จะไม่ส่งคืนชุดข้อมูลเดียวกันกับGROUP BYแบบสอบถามหรือไม่ อะไรคือเหตุผลในการเลือกอย่างใดอย่างหนึ่ง?
Erick 3E

3
@ Erick3E โปรดดูคำถามนี้stackoverflow.com/questions/20375074/…
Arunprasanth KV

ฉันชอบคำตอบนี้ดีกว่าเพราะมันแสดงให้เห็นว่าการทำงานของฟังก์ชันการรวมขั้นต่ำ / สูงสุด / ผลรวมในพาร์ติชัน ตัวอย่าง Row_Number () ไม่ได้ทำให้ชัดเจน ปกติฉันใช้ฟังก์ชั่นรวมกับ GROUP BY แต่เพิ่งสังเกตเห็นว่า PARTITION-OVER มีวิธีการเดียวกันและสงสัยในสิ่งเดียวกันกับที่ OP ทำ - ซึ่งทำให้ฉันอยู่ที่นี่ ขอบคุณ!
ripvlan

53

partition byไม่ได้รวมข้อมูลจริง ๆ จะช่วยให้คุณสามารถรีเซ็ตบางสิ่งในแต่ละกลุ่ม ตัวอย่างเช่นคุณสามารถรับคอลัมน์ลำดับภายในกลุ่มโดยการแบ่งพาร์ติชันในฟิลด์การจัดกลุ่มและใช้rownum()มากกว่าแถวภายในกลุ่มนั้น สิ่งนี้จะให้สิ่งที่คุณมีลักษณะคล้ายกับคอลัมน์ข้อมูลประจำตัวที่ตั้งค่าใหม่ในตอนต้นของแต่ละกลุ่ม


43

PARTITION โดยแบ่งผลลัพธ์ที่กำหนดไว้ในพาร์ติชัน ฟังก์ชั่นหน้าต่างถูกนำไปใช้กับแต่ละพาร์ติชันแยกจากกันและการคำนวณรีสตาร์ทสำหรับแต่ละพาร์ติชัน

พบได้ที่ลิงค์นี้: OVER Clause


36

มันให้ข้อมูลที่รีดขึ้นโดยไม่ต้องม้วนขึ้น

เช่นสมมติว่าฉันต้องการส่งคืนตำแหน่งสัมพัทธ์ของภูมิภาคการขาย

เมื่อใช้พาร์ติชันโดยฉันสามารถส่งคืนยอดขายสำหรับภูมิภาคที่ระบุและจำนวนสูงสุดในภูมิภาคการขายทั้งหมดในแถวเดียวกัน

นี่หมายความว่าคุณจะมีข้อมูลที่ซ้ำกัน แต่อาจเหมาะกับผู้บริโภคปลายทางในแง่ที่ว่าข้อมูลถูกรวมเข้าด้วยกัน แต่ไม่มีข้อมูลใดสูญหาย - เช่นกรณีของ GROUP BY


3
คำตอบที่ดีที่สุดและง่ายที่สุด
tmthyjames

27

PARTITION BYคือการวิเคราะห์ในขณะที่GROUP BYรวม เพื่อการใช้งานPARTITION BYที่คุณต้องมีมันกับประโยคขึ้นไป


1
PARTITION BY is analyticคำแถลงง่ายๆนี้เคลียร์มากสำหรับฉัน +1

นี่เป็นคำตอบที่ง่ายและดีที่สุด
jdmneon

22

จากความเข้าใจของฉัน Partition By เกือบจะเหมือนกับ Group By แต่มีความแตกต่างดังต่อไปนี้:

กลุ่มนั้นโดยกลุ่มจริง ๆ แล้วชุดผลลัพธ์ส่งคืนหนึ่งแถวต่อกลุ่มซึ่งผลลัพธ์ใน SQL Server จะอนุญาตเฉพาะในฟังก์ชันรายการรวมคอลัมน์หรือรายการที่เป็นส่วนหนึ่งของกลุ่มตามข้อ (ในกรณีที่ SQL Server สามารถรับประกันได้ว่ามีเฉพาะ ผลลัพธ์สำหรับแต่ละกลุ่ม)

พิจารณาตัวอย่าง MySQL ที่อนุญาตให้มีในคอลัมน์รายการ SELECT ที่ไม่ได้กำหนดไว้ใน Group By clause ซึ่งในกรณีนี้หนึ่งแถวยังคงถูกส่งคืนต่อกลุ่มอย่างไรก็ตามถ้าคอลัมน์ไม่มีผลลัพธ์ที่ไม่ซ้ำกันจะไม่มีการรับประกัน สิ่งที่จะส่งออก!

แต่ด้วย Partition By แม้ว่าผลลัพธ์ของฟังก์ชันจะเหมือนกับผลลัพธ์ของฟังก์ชันการรวมกับ Group By แต่คุณก็ยังได้รับชุดผลลัพธ์ปกติซึ่งหมายความว่ามีการรับหนึ่งแถวต่อแถวที่อยู่ข้างใต้และไม่ใช่หนึ่งแถวต่อ กลุ่มและเนื่องจากสิ่งนี้สามารถมีคอลัมน์ที่ไม่ซ้ำกันต่อกลุ่มในรายการ SELECT

ดังนั้นโดยสรุป Group By จะดีที่สุดเมื่อต้องการเอาต์พุตหนึ่งแถวต่อกลุ่มและ Partition By จะดีที่สุดเมื่อต้องการแถวทั้งหมด แต่ยังต้องการฟังก์ชันรวมตามกลุ่ม

แน่นอนอาจจะมีปัญหาประสิทธิภาพการทำงานให้ดูhttp://social.msdn.microsoft.com/Forums/ms-MY/transactsql/thread/0b20c2b5-1607-40bc-b7a7-0c60a2a55fba


2

เมื่อคุณใช้งานGROUP BYแถวผลลัพธ์มักจะน้อยกว่าแถวที่เข้ามา

แต่เมื่อคุณใช้PARTITION BYการนับแถวผลลัพธ์ควรเหมือนกับขาเข้า


0

สมมติว่าเรามี 14 ระเบียนของnameคอลัมน์ในตาราง

ใน group by

select name,count(*) as totalcount from person where name='Please fill out' group BY name;

มันจะนับเป็นแถวเดียวเช่น 14

แต่ใน partition by

select row_number() over (partition by name) as total from person where name = 'Please fill out';

มันจะเพิ่มจำนวนแถว 14 แถว


0

การสังเกตขนาดเล็ก กลไกการทำงานอัตโนมัติเพื่อสร้าง SQL แบบไดนามิกโดยใช้ 'พาร์ติชันโดย' มันง่ายกว่ามากในการใช้งานที่เกี่ยวข้องกับ 'กลุ่มโดย' ในกรณีของ 'จัดกลุ่มตาม' เราต้องดูแลเนื้อหาของคอลัมน์ 'เลือก'

ขอโทษสำหรับภาษาอังกฤษของฉัน


0

มันมีสถานการณ์การใช้งานที่แตกต่างกันจริงๆ เมื่อคุณใช้ GROUP BY คุณจะรวมบางระเบียนสำหรับคอลัมน์ที่เหมือนกันและคุณมีการรวมชุดผลลัพธ์

อย่างไรก็ตามเมื่อคุณใช้ PARTITION ตามชุดผลลัพธ์ของคุณจะเหมือนกัน แต่คุณมีการรวมฟังก์ชันหน้าต่างและคุณไม่รวมระเบียนคุณจะยังคงมีจำนวนระเบียนเท่าเดิม

นี่คือบทความที่เป็นประโยชน์ของการชุมนุมอธิบายความแตกต่าง: http://alevryustemov.com/sql/sql-partition-by/


-1
-- BELOW IS A SAMPLE WHICH OUTLINES THE SIMPLE DIFFERENCES
-- READ IT AND THEN EXECUTE IT
-- THERE ARE THREE ROWS OF EACH COLOR INSERTED INTO THE TABLE
-- CREATE A database called testDB


-- use testDB
USE [TestDB]
GO


-- create Paints table
CREATE TABLE [dbo].[Paints](
    [Color] [varchar](50) NULL,
    [glossLevel] [varchar](50) NULL
) ON [PRIMARY]

GO


-- Populate Table
insert into paints (color, glossLevel)
select 'red', 'eggshell'
union
select 'red', 'glossy'
union
select 'red', 'flat'
union
select 'blue', 'eggshell'
union
select 'blue', 'glossy'
union
select 'blue', 'flat'
union
select 'orange', 'glossy'
union
select 'orange', 'flat'
union
select 'orange', 'eggshell'
union
select 'green', 'eggshell'
union
select 'green', 'glossy'
union
select 'green', 'flat'
union
select 'black', 'eggshell'
union
select 'black', 'glossy'
union
select 'black', 'flat'
union
select 'purple', 'eggshell'
union
select 'purple', 'glossy'
union
select 'purple', 'flat'
union
select 'salmon', 'eggshell'
union
select 'salmon', 'glossy'
union
select 'salmon', 'flat'


/*   COMPARE 'GROUP BY' color to 'OVER (PARTITION BY Color)'  */

-- GROUP BY Color 
-- row quantity defined by group by
-- aggregate (count(*)) defined by group by
select count(*) from paints
group by color

-- OVER (PARTITION BY... Color 
-- row quantity defined by main query
-- aggregate defined by OVER-PARTITION BY
select color
, glossLevel
, count(*) OVER (Partition by color)
from paints

/* COMPARE 'GROUP BY' color, glossLevel to 'OVER (PARTITION BY Color, GlossLevel)'  */

-- GROUP BY Color, GlossLevel
-- row quantity defined by GROUP BY
-- aggregate (count(*)) defined by GROUP BY
select count(*) from paints
group by color, glossLevel



-- Partition by Color, GlossLevel
-- row quantity defined by main query
-- aggregate (count(*)) defined by OVER-PARTITION BY
select color
, glossLevel
, count(*) OVER (Partition by color, glossLevel)
from paints
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.