SQL Server: разница между PARTITION BY и GROUP BY


366

Я использовал GROUP BYдля всех типов совокупных запросов на протяжении многих лет. Недавно я провел обратный инжиниринг кода, который используется PARTITION BYдля агрегации. Прочитав всю документацию, которую я могу найти PARTITION BY, это звучит очень похоже GROUP BY, может быть, с добавлением немного дополнительной функциональности? Это две версии одного и того же общего функционала или они что-то совершенно другое?

Ответы:


441

Они используются в разных местах. 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Обычно A уменьшает количество возвращаемых строк, сворачивая их и вычисляя средние или суммы для каждой строки. partition byне влияет на количество возвращаемых строк, но меняет способ вычисления результата оконной функции.


23
хороший ответ, не могли бы вы написать пример возвращаемых результатов для каждого из них?
Ашкан Мобаен Хиабани

2
@AshkanMobayenKhiabani вы можете выполнить оба запроса к Northwind, который может быть установлен или не установлен по умолчанию в зависимости от версии вашего сервера sql. Если нет, вы можете найти его на странице загрузок.
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запрос? Каковы причины выбора одного или другого?
Эрик 3Е

3
@ Erick3E, пожалуйста, взгляните на этот вопрос stackoverflow.com/questions/20375074/…
Arunprasanth KV

Мне больше нравится этот ответ, потому что он показывает, как агрегирующие функции Min / Max / Sum и т. Д. Работают на разделах. Пример Row_Number () не дает ясности. Обычно я использую агрегатную функцию с GROUP BY, но только что заметил, что PARTITION-OVER имеет те же методы и удивился тому же, что и OP - что привело меня сюда. Спасибо!
ripvlan

53

partition byна самом деле не свернуть данные. Это позволяет вам сбросить что-то для каждой группы. Например, вы можете получить порядковый столбец в группе, разделив поле группировки и используя rownum()строки в этой группе. Это дает вам нечто похожее на столбец идентификаторов, который сбрасывается в начале каждой группы.


43

PARTITION BY Делит результирующий набор на разделы. Функция окна применяется к каждому разделу отдельно, и вычисление перезапускается для каждого раздела.

Найдено по этой ссылке: OVER Clause


36

Предоставляет свернутые данные без свертывания

т.е. предположим, что я хочу вернуть относительную позицию региона продаж

Используя PARTITION BY, я могу вернуть сумму продаж для данного региона и максимальную сумму для всех регионов продаж в одной строке.

Это означает, что у вас будут повторяющиеся данные, но они могут подойти конечному потребителю в том смысле, что данные были агрегированы, но данные не были потеряны - как в случае с GROUP BY.


3
Лучший, самый простой ответ.
tmthyjames

27

PARTITION BYаналитичен, а GROUP BYагрегатен. Чтобы использовать PARTITION BY, вы должны содержать его с предложением OVER .


1
PARTITION BY is analyticэто простое утверждение многое прояснило для меня. +1.

На самом деле это самый простой и лучший ответ.
jdmneon

22

Насколько я понимаю, раздел By почти идентичен группе By, но со следующими отличиями:

Эта группа фактически группирует результирующий набор, возвращая по одной строке на группу, что приводит к тому, что SQL Server допускает только агрегированные функции списка SELECT или столбцы, которые являются частью предложения group by (в этом случае SQL Server может гарантировать, что существуют уникальные результаты для каждой группы).

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

Но с Partition By, хотя результаты функции идентичны результатам агрегатной функции с Group By, вы все равно получаете нормальный набор результатов, что означает, что каждый получает одну строку на базовую строку, а не одну строку на group, и из-за этого в списке 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 с использованием «разбиения по» гораздо проще реализовать по отношению к «группированию по». В случае «group by», мы должны позаботиться о содержимом столбца «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.