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. Якщо ні, ви можете шукати його на сторінці завантажень s.
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

Перш ніж перейти до PARTITION BY, давайте подивимось на OVERпункт:

Відповідно до визначення MSDN:

Пункт OVER визначає вікно або вказаний користувачем набір рядків у наборі результатів запиту. Потім функція вікна обчислює значення для кожного рядка у вікні. Ви можете використовувати пункт OVER з функціями для обчислення агрегованих значень, таких як ковзаючі середні показники, сукупні агрегати, підсумкові підсумки або результати N на верхній групі.

PARTITION BY не зменшить кількість повернених рядків.

Ми можемо застосувати PARTITION BY у нашій прикладі таблиці:

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

Мені ця відповідь більше подобається, тому що вона показує, як функції «Сукупність» Min / Max / Sum тощо працюють над розділами. Приклад Row_Number () не робить це зрозумілим. Зазвичай я використовую сукупну функцію з GROUP BY, але щойно помітив, що PARTITION-OVER має ті самі методи, і дивувався тому ж, що робив ОП - які ведуть мене сюди. Дякую!
ripvlan

53

partition byнасправді не збиває дані. Це дозволяє скинути щось на груповій основі. Наприклад, ви можете отримати порядковий стовпчик у групі, розділивши на поле групування та використовуючи rownum()над рядками в цій групі. Це дає вам щось, що трохи схоже на стовпець ідентифікації, який скидається на початку кожної групи.


43

РОЗДІЛ ЗА РОЗДІЛЕННЯМ Розділяє результат, встановлений на розділи. Функція вікна застосовується до кожного розділу окремо і обчислення перезапускається для кожного розділу.

Знайдено за цим посиланням: ЗАКЛАД ОКОН


36

Він надає зведені дані без згортання

Припустимо, я хочу повернути відносне положення регіону продажу

Використовуючи PARTITION BY, я можу повернути суму продажів для даного регіону та суму MAX у всіх регіонах продажу в одному рядку.

Це означає, що у вас будуть повторювані дані, але це може подобатися кінцевому споживачеві в тому сенсі, що дані були зібрані, але жодних даних не було втрачено - як це було у випадку з GROUP BY.


3
Найкраща, найпростіша відповідь.
tmthyjames

27

PARTITION BYє аналітичним, тоді як GROUP BYє сукупним. Для того, щоб використовувати PARTITION BY, ви повинні містити його із застереженням OVER .


1
PARTITION BY is analyticце просте твердження для мене багато чого прояснило. +1.

Це насправді найпростіша і найкраща відповідь.
jdmneon

22

На мій погляд, Partition By майже ідентичний Group By, але з такими відмінностями:

Ця група фактично групує набір результатів, що повертає один рядок на групу, що призводить до того, що SQL Server дозволяє лише в списку SELECT сукупних функцій або стовпців, що входять до групи за пунктом (у цьому випадку SQL Server може гарантувати наявність унікальних результати для кожної групи).

Розглянемо, наприклад, MySQL, який дозволяє містити у списку SELECT стовпці, які не визначені у групі за пунктом, у цьому випадку один рядок все ще повертається для кожної групи, однак якщо стовпець не має унікальних результатів, то гарантії немає. який буде вихід!

Але з розділом By, хоча результати функції ідентичні результатам сукупної функції з Group By, все ж ви отримуєте звичайний набір результатів, що означає, що ви отримуєте один рядок на нижчий рядок, а не один рядок на група, і через це в списку SELECT можуть бути стовпці, які не є унікальними для кожної групи.

Отже, як підсумок, група "Групи" була б найкращою, коли потрібен вихід у один рядок на групу, а "Розділ" - найкращий, коли потрібні всі рядки, але все-таки хоче функція сукупності на основі групи.

Звичайно, можуть виникнути проблеми з ефективністю, див. 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 за допомогою 'розділу за' набагато простіше реалізувати стосовно до 'групи за допомогою'. У випадку "групи за" ми повинні подбати про вміст стовпця "select".

Вибачте за мою англійську.


0

У нього дійсно різні сценарії використання. Коли ви використовуєте GROUP BY, ви об'єднуєте деякі записи для однакових стовпців і у вас є агрегація набору результатів.

Однак, коли ви використовуєте PARTITION BY, ваш набір результатів однаковий, але у вас просто агрегація над віконними функціями, і ви не об'єднуєте записи, ви все одно будете мати однаковий кількість записів.

Ось корисна стаття для мітингу, що пояснює різницю: 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.