Одной из лучших функций в SQL являются оконные функции . Дмитрий Фонтейн выразился прямо:
Был SQL перед оконными функциями и SQL после оконных функций
Если вам повезло использовать любую из этих баз данных, то вы можете использовать оконные функции самостоятельно:
- CUBRID
- DB2
- жар-птица
- Informix
- оракул
- PostgreSQL
- SQL Server
- Sybase SQL Anywhere
- Teradata
Одним из наиболее очевидных и полезных наборов оконных функций являются функции ранжирования, в которых строки из вашего набора результатов ранжируются в соответствии с определенной схемой. Есть три функции ранжирования:
ROW_NUMBER()
RANK()
DENSE_RANK()
Разницу легко запомнить. Для примеров, давайте предположим, что у нас есть эта таблица (с использованием синтаксиса PostgreSQL):
CREATE TABLE t(v) AS
SELECT * FROM (
VALUES('a'),('a'),('a'),('b'),
('c'),('c'),('d'),('e')
) t(v)
ROW_NUMBER ()
… Присваивает уникальные номера каждой строке в PARTITION
данном ORDER BY
предложении. Итак, вы получите:
SELECT v, ROW_NUMBER() OVER()
FROM t
Обратите внимание, что некоторые диалекты SQL (например, SQL Server) требуют явного ORDER BY
предложения в OVER()
предложении:
SELECT v, ROW_NUMBER() OVER(ORDER BY v)
FROM t
Приведенный выше запрос возвращает:
РАНГ()
… Ведет себя так ROW_NUMBER()
, за исключением того, что «равные» строки ранжируются одинаково. Если мы подставим RANK()
в наш предыдущий запрос:
SELECT v, RANK() OVER(ORDER BY v)
FROM t
… тогда мы получаем следующий результат:
Как видите, как и в спортивном рейтинге, у нас есть разрывы между различными рангами. Мы можем избежать этих пробелов, используя
DENSE_RANK ()
Тривиально, DENSE_RANK()
это ранг без пробелов, т.е. он «плотный» . Мы можем написать:
SELECT v, DENSE_RANK() OVER(ORDER BY v)
FROM t
… чтобы получить
Одним интересным аспектом DENSE_RANK()
является тот факт, что он «ведет себя как», ROW_NUMBER()
когда мы добавляем DISTINCT
ключевое слово .
SELECT DISTINCT v, DENSE_RANK() OVER(ORDER BY v)
FROM t
… чтобы получить
На самом деле, не ROW_NUMBER()
позволяет использовать DISTINCT
, потому что ROW_NUMBER()
генерирует уникальные значения в разделе передDISTINCT
применением:
SELECT DISTINCT v, ROW_NUMBER() OVER(ORDER BY v)
FROM t
ORDER BY 1, 2
DISTINCT
не имеет никакого эффекта:
Собираем все вместе
Хороший способ понять три функции ранжирования — это увидеть их все в действии бок о бок. Запустите этот запрос
SELECT
v,
ROW_NUMBER() OVER(ORDER BY v),
RANK() OVER(ORDER BY v),
DENSE_RANK() OVER(ORDER BY v)
FROM t
ORDER BY 1, 2
… Или этот (используя стандартное WINDOW
предложение SQL , чтобы повторно использовать спецификации окон):
SELECT
v,
ROW_NUMBER() OVER(w),
RANK() OVER(w),
DENSE_RANK() OVER(w)
FROM t
WINDOW w AS (ORDER BY v)
… чтобы получить:
Обратите внимание, что, к сожалению, это WINDOW
предложение поддерживается не во всех базах данных.
SQL потрясающий
Эти вещи можно написать очень легко с помощью оконных функций SQL. Как только вы освоите синтаксис, вы больше не захотите пропускать эту убойную функцию в своих ежедневных SQL-выражениях. В восторге?
Для дальнейшего чтения рассмотрим:
- Руководства jOOQ по оконным функциям
- Отличная статья Дмитрия Фонтейна «Понимание оконных функций»
- Реальный пример использования: подсчет соседних цветов в хореографии стадиона
- Реальный пример использования: вычисление промежуточных итогов (не только с оконными функциями)
- SQL 101: окно в мир аналитических функций