Ключевое слово Oracle «Partition By»

254

Может кто-нибудь объяснить, что partition byделает ключевое слово, и дать простой пример его в действии, а также почему можно его использовать? У меня есть SQL-запрос, написанный кем-то другим, и я пытаюсь выяснить, что он делает.

Пример разбиения по:

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

Примеры, которые я видел в Интернете, кажутся слишком глубокими.

Алекс Бердсли
источник
Другая важная ссылка: postgresql.org/docs/9.1/static/tutorial-window.html
Шашанк Вивек,

Ответы:

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
1
Вы имеете в виду "без суб-выбора, который намного медленнее"? Я думаю, я запутался, если суб-выбор медленнее или быстрее, чем last overи min over. Я полагаю, что дополнительный выбор будет медленнее, но английская грамматика в ответе не предполагает этого.
Джейсон
Такой подход уменьшает количество обработанных строк, что делает его более эффективным, чем подвыбор. Наиболее заметно в очень больших наборах данных.
Парень
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?
Кевин Бертон,
Я предлагаю вам задать вопрос о SO, дать конкретику и объяснить, чего вы хотите достичь
Andrejs
@ Viuu-a: Тогда вы, вероятно, захотите использовать простой GROUP BY.
Джекхипстер
люблю этот пример ... легко понять
Джонни Ву
27

Это расширение SQL называется аналитикой. «Over» в операторе select говорит оракулу, что функция является аналитической функцией, а не группой по функции. Преимущество использования аналитики состоит в том, что вы можете собирать суммы, числа и многое другое всего за один проход данных вместо того, чтобы циклически перебирать данные с помощью подвыборок или, еще хуже, PL / SQL.

Поначалу это выглядит странно, но это быстро станет второй натурой. Никто не объясняет это лучше, чем Том Кайт. Так что ссылка выше отличная.

Конечно, чтение документации обязательно.

user60890
источник
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

Здесь мы рассчитываем на соответствующую дептно. Что касается 10, у нас есть 4 записи в таблице emp, аналогичные результаты также для 20 и 30.


источник
12
Нет возражений на вопрос, как работает PARTITION. Только пример выходных данных не полностью отвечает на вопрос.
Сирадж Самсудин
2

ключевое слово over partition выглядит так, как будто мы разделяем данные с помощью 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

Issam
источник
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.

georgejo
источник