SQL Server: Perbedaan antara PARTITION BY dan GROUP BY

366

Saya telah menggunakan GROUP BYuntuk semua jenis kueri agregat selama bertahun-tahun. Baru-baru ini, saya telah melakukan rekayasa balik terhadap beberapa kode yang digunakan PARTITION BYuntuk melakukan agregasi. Dalam membaca semua dokumentasi yang bisa saya temukan PARTITION BY, kedengarannya seperti GROUP BY, mungkin dengan sedikit fungsionalitas tambahan? Apakah mereka dua versi dari fungsi umum yang sama, atau mereka sesuatu yang sama sekali berbeda?

Mike Mooney
sumber

Jawaban:

441

Mereka digunakan di tempat yang berbeda. group bymengubah seluruh permintaan, seperti:

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

Tetapi partition byhanya berfungsi pada fungsi jendela , seperti row_number:

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

A group bybiasanya mengurangi jumlah baris yang dikembalikan dengan menggulungnya dan menghitung rata-rata atau jumlah untuk setiap baris. partition bytidak mempengaruhi jumlah baris yang dikembalikan, tetapi itu mengubah cara hasil fungsi jendela dihitung.

Andomar
sumber
23
jawaban yang bagus, tolong tulis sampel hasil yang dikembalikan untuk masing-masing
Ashkan Mobayen Khiabani
2
@AshkanMobayenKhiabani Anda dapat menjalankan kedua permintaan terhadap Northwind, yang mungkin atau mungkin tidak diinstal secara default tergantung pada versi server sql Anda. Jika tidak, Anda dapat mencarinya di halaman unduhan.
Fetchez la vache
15
@AshkanMobayenKhiabani Jawaban Arunprasanth di bawah ini menunjukkan hasil yang dapat menghemat waktu Anda daripada melompat melalui lebih banyak rintangan pembelajaran dan waktu untuk belajar Northwind
Praxiteles
1
Lebih lanjut tentang fungsi windows (dalam SQL): blog.jooq.org/2013/11/03/…
datps
itcodehub.blogspot.com/2019/03/... - info lebih lanjut dan contoh tentang perbedaan antara grup dengan dan partisi oleh di sql
xproph
252

Kita dapat mengambil contoh sederhana.

Pertimbangkan sebuah tabel bernama TableA dengan nilai berikut:

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

Klausa SQL GROUP BY dapat digunakan dalam pernyataan SELECT untuk mengumpulkan data di beberapa rekaman dan mengelompokkan hasil dengan satu atau beberapa kolom.

Dengan kata yang lebih sederhana, pernyataan GROUP BY digunakan bersama dengan fungsi agregat untuk mengelompokkan hasil yang ditetapkan oleh satu atau beberapa kolom.

Sintaksis:

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

Kita dapat mendaftar GROUP BYdi tabel kami:

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

Hasil:

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

Dalam tabel asli kami, kami memiliki 7 baris dan ketika kami menerapkan GROUP BY id , server mengelompokkan hasil berdasarkan id:

Dengan kata sederhana:

di sini GROUP BYbiasanya mengurangi jumlah baris yang dikembalikan dengan menggulung dan menghitung Sum()untuk setiap baris.

PARTITION BY

Sebelum pergi ke PARTITION OLEH, mari kita lihat OVER klausa:

Menurut definisi MSDN:

Klausa OVER mendefinisikan jendela atau kumpulan baris yang ditentukan pengguna dalam kumpulan hasil kueri. Fungsi jendela kemudian menghitung nilai untuk setiap baris di jendela. Anda dapat menggunakan klausa OVER dengan fungsi untuk menghitung nilai agregat seperti rata-rata bergerak, agregat kumulatif, total berjalan, atau hasil N teratas per grup.

PARTITION BY tidak akan mengurangi jumlah baris yang dikembalikan.

Kita dapat menerapkan PARTITION BY dalam contoh tabel kita:

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

Hasil:

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

Lihatlah hasilnya - ini akan mempartisi baris dan mengembalikan semua baris, tidak seperti GROUP BY.

Arunprasanth KV
sumber
3
partition by dapat mempengaruhi jumlah baris, hanya saja tidak akan mengurangi jumlah baris.
John
1
Apa perbedaannya jika saya mengubah ke SELECTdalam SELECT DISTINCTke permintaan kedua? bukankah itu mengembalikan set data yang sama dengan GROUP BYkueri? Apa alasan memilih satu atau yang lain?
Erick 3E
3
@ Erick3E silakan lihat pertanyaan ini stackoverflow.com/questions/20375074/…
Arunprasanth KV
Saya suka jawaban ini lebih baik karena ini menunjukkan bagaimana fungsi Agregat Min / Max / Sum dll bekerja pada Partisi. Contoh Row_Number () tidak menjelaskannya. Biasanya saya menggunakan fungsi agregat dengan GROUP BY tetapi hanya memperhatikan bahwa PARTITION-OVER memiliki metode yang sama dan bertanya-tanya hal yang sama dengan OP - yang membawa saya ke sini. Terima kasih!
ripvlan
53

partition bysebenarnya tidak menggulung data. Ini memungkinkan Anda untuk mereset sesuatu berdasarkan per grup. Misalnya, Anda bisa mendapatkan kolom ordinal dalam grup dengan mempartisi pada bidang pengelompokan dan menggunakan rownum()lebih dari baris dalam grup itu. Ini memberi Anda sesuatu yang berperilaku sedikit seperti kolom identitas yang diatur ulang di awal setiap grup.

ConcernedOfTunbridgeWells
sumber
43

PARTISI DENGAN Membagi hasil yang ditetapkan ke dalam partisi. Fungsi jendela diterapkan ke setiap partisi secara terpisah dan perhitungan dimulai ulang untuk setiap partisi.

Ditemukan di tautan ini: OVER Clause

Will Marcouiller
sumber
36

Ini memberikan data yang digulung tanpa menggulung

misalkan saya ingin mengembalikan posisi relatif wilayah penjualan

Menggunakan PARTISI OLEH, saya bisa mengembalikan jumlah penjualan untuk wilayah tertentu dan jumlah MAX di semua wilayah penjualan di baris yang sama.

Ini berarti Anda akan memiliki data berulang, tetapi mungkin sesuai dengan konsumen akhir dalam arti bahwa data telah dikumpulkan tetapi tidak ada data yang hilang - seperti halnya dengan GROUP BY.

Adolf bawang putih
sumber
3
Jawaban terbaik dan paling sederhana.
tmthyjames
27

PARTITION BYanalitik, sementara GROUP BYagregat. Untuk menggunakan PARTITION BY, Anda harus mengisinya dengan klausa OVER .

OMG Ponies
sumber
1
PARTITION BY is analyticpernyataan sederhana ini sangat membantu saya. +1.
Ini sebenarnya jawaban paling sederhana dan terbaik.
jdmneon
22

Pada pemahaman saya, Partition By hampir identik dengan Group By, tetapi dengan perbedaan berikut:

Grup itu dengan benar-benar mengelompokkan hasil yang diatur mengembalikan satu baris per grup, yang karenanya menghasilkan SQL Server hanya memungkinkan dalam fungsi agregat daftar SELECT atau kolom yang merupakan bagian dari grup dengan klausa (dalam hal ini SQL Server dapat menjamin bahwa ada yang unik hasil untuk setiap kelompok).

Sebagai contoh, perhatikan MySQL yang memungkinkan untuk ada di kolom daftar SELECT yang tidak didefinisikan dalam klausa Kelompok Menurut, dalam hal ini satu baris masih dikembalikan per grup, namun jika kolom tidak memiliki hasil yang unik maka tidak ada jaminan apa yang akan menjadi output!

Tetapi dengan Partition By, meskipun hasil fungsi identik dengan hasil fungsi agregat dengan Group By, Anda tetap mendapatkan hasil normal, yang berarti bahwa seseorang mendapatkan satu baris per baris yang mendasarinya, dan bukan satu baris per grup, dan karena yang ini dapat memiliki kolom yang tidak unik per grup dalam daftar SELECT.

Jadi sebagai ringkasan, Group By akan menjadi yang terbaik ketika membutuhkan output dari satu baris per grup, dan Partition By akan menjadi yang terbaik ketika seseorang membutuhkan semua baris tetapi masih menginginkan fungsi agregat berdasarkan pada grup.

Tentu saja mungkin juga ada masalah kinerja, lihat http://social.msdn.microsoft.com/Forums/ms-MY/transactsql/thread/0b20c2b5-1607-40bc-b7a7-0c60a2a55fba .

halo yoel
sumber
2

Saat Anda menggunakan GROUP BY , baris yang dihasilkan biasanya kurang dari baris yang masuk.

Tetapi, ketika Anda menggunakan PARTITION BY, jumlah baris yang dihasilkan harus sama dengan yang masuk.

Mahdi Ben Selimene
sumber
0

Misalkan kita memiliki 14 catatan name kolom dalam tabel

di group by

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

itu akan memberikan hitungan dalam satu baris yaitu 14

tapi di partition by

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

itu akan 14 baris peningkatan hitungan

Ambrish Rajput
sumber
0

Pengamatan kecil. Mekanisme otomasi untuk secara dinamis menghasilkan SQL menggunakan 'partisi dengan' itu jauh lebih mudah untuk diterapkan dalam kaitannya dengan 'grup oleh'. Dalam hal 'dikelompokkan berdasarkan', Kami harus menjaga konten kolom 'pilih'.

Maaf untuk Bahasa Inggris Saya.

pengguna1785960
sumber
0

Ini memiliki skenario penggunaan yang sangat berbeda. Saat Anda menggunakan GROUP BY, Anda menggabungkan beberapa catatan untuk kolom yang sama dan Anda memiliki kumpulan kumpulan hasil.

Namun ketika Anda menggunakan PARTISI DENGAN set hasil Anda sama tetapi Anda hanya memiliki agregasi atas fungsi jendela dan Anda tidak menggabungkan catatan, Anda masih akan memiliki jumlah catatan yang sama.

Berikut ini adalah artikel bermanfaat yang menjelaskan perbedaannya: http://alevryustemov.com/sql/sql-partition-by/

Alev Ryustemov
sumber
-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
Peoria Os
sumber