В этом уроке мы познакомимся с функцией ROW_NUMBER()
, «номер строки». Эта функция присваивает каждой строке уникальный номер в рамках группы. Соответственно, максимальное значение ROW_NUMBER()
у нас может совпадать с количеством строк в таблице, но это не обязательно.
Функция ROW_NUMBER()
помогает задать нумерацию, которая будет отличаться от порядка сортировки строк результирующего набора. Допустим, вам нужно пронумеровать строки — то есть поставить номер строки. При этом нужно работать не со всеми записями в таблицах, а только в определенных разрезах или по определенной логике.
Использование ROW_NUMBER
Используем ROW_NUMBER() OVER ()
, чтобы пронумеровать продажи
SELECT
id,
sale_date,
quantity,
price,
ROW_NUMBER() OVER () AS sale_number
FROM sales;
id | sale_date | quantity | price | sale_number |
---|---|---|---|---|
1 | 2023-01-01T00:00:00.000Z | 1 | 4 | 1 |
2 | 2023-01-01T00:00:00.000Z | 2 | 2 | 2 |
3 | 2023-01-01T00:00:00.000Z | 1 | 1 | 3 |
4 | 2023-01-01T00:00:00.000Z | 1 | 2 | 4 |
5 | 2023-01-02T00:00:00.000Z | 1 | 3 | 5 |
6 | 2023-01-02T00:00:00.000Z | 1 | 3 | 6 |
7 | 2023-01-03T00:00:00.000Z | 1 | 1 | 7 |
8 | 2023-01-03T00:00:00.000Z | 1 | 3 | 8 |
9 | 2023-01-03T00:00:00.000Z | 1 | 1 | 9 |
10 | 2023-01-03T00:00:00.000Z | 1 | 1 | 10 |
... |
View on DB Fiddle
В столбце sale_number
каждая строка имеет уникальный номер продажи. Нумерация начинается с 1 и увеличивается на 1 для каждой следующей строки.
Расширим функцию и добавим партици. Следующий запрос присваивает уникальный номер каждой строке внутри каждой группы, определенной PARTITION BY
.
SELECT
id,
sale_date,
quantity,
price,
ROW_NUMBER() OVER (PARTITION BY sale_date) AS sale_number
FROM sales;
id | sale_date | quantity | price | sale_number |
---|---|---|---|---|
1 | 2023-01-01T00:00:00.000Z | 1 | 4 | 1 |
2 | 2023-01-01T00:00:00.000Z | 2 | 2 | 2 |
3 | 2023-01-01T00:00:00.000Z | 1 | 1 | 3 |
4 | 2023-01-01T00:00:00.000Z | 1 | 2 | 4 |
5 | 2023-01-02T00:00:00.000Z | 1 | 3 | 1 |
6 | 2023-01-02T00:00:00.000Z | 1 | 3 | 2 |
7 | 2023-01-03T00:00:00.000Z | 1 | 1 | 1 |
8 | 2023-01-03T00:00:00.000Z | 1 | 3 | 2 |
9 | 2023-01-03T00:00:00.000Z | 1 | 1 | 3 |
10 | 2023-01-03T00:00:00.000Z | 1 | 1 | 4 |
11 | 2023-01-03T00:00:00.000Z | 1 | 2 | 5 |
... |
View on DB Fiddle
Разберем подробно запрос. PARTITION BY sale_date
- создает группы, окна, по уникальной дате продаже. ROW_NUMBER() OVER (PARTITION BY sale_date) AS sale_number
- применяет функцию ROW_NUMBER() к каждой строке данных внутри группы. Таким образом, каждая строка внутри каждой группы будет иметь уникальный номер, который будет отображаться в столбце sale_number
.
Внутри оператора OVER ()
можем использовать сортировку, чтобы указать порядок для нумерации строк.
SELECT
id,
sale_date,
quantity,
price,
row_number() OVER (PARTITION BY sale_date ORDER BY quantity) AS sale_number
FROM sales;
id | sale_date | quantity | price | sale_number |
---|---|---|---|---|
4 | 2023-01-01T00:00:00.000Z | 1 | 2 | 1 |
1 | 2023-01-01T00:00:00.000Z | 1 | 4 | 2 |
3 | 2023-01-01T00:00:00.000Z | 1 | 1 | 3 |
2 | 2023-01-01T00:00:00.000Z | 2 | 2 | 4 |
5 | 2023-01-02T00:00:00.000Z | 1 | 3 | 1 |
6 | 2023-01-02T00:00:00.000Z | 1 | 3 | 2 |
7 | 2023-01-03T00:00:00.000Z | 1 | 1 | 1 |
8 | 2023-01-03T00:00:00.000Z | 1 | 3 | 2 |
9 | 2023-01-03T00:00:00.000Z | 1 | 1 | 3 |
10 | 2023-01-03T00:00:00.000Z | 1 | 1 | 4 |
11 | 2023-01-03T00:00:00.000Z | 1 | 2 | 5 |
... |
View on DB Fiddle
Теперь порядок строк изменился. На первом месте запись с id = 4, но результат может меняться, так как в колонке quantity у нескольких записей одинаковые значения. При сортировке лучше использовать поля или значения, которые помогут однозначно отсортировать значения, например дата продажи с точностью до секунды.
Для сортировки можно также использовать вычисляемые значения
SELECT
id,
sale_date,
quantity,
price,
(quantity * price) AS amount,
row_number()
OVER (PARTITION BY sale_date ORDER BY quantity * price DESC)
AS sale_number
FROM sales
WHERE sale_date = '01.01.2023' ORDER BY sale_number ASC;
id | sale_date | quantity | price | amount | sale_number |
---|---|---|---|---|---|
1 | 2023-01-01T00:00:00.000Z | 1 | 4 | 4 | 1 |
2 | 2023-01-01T00:00:00.000Z | 2 | 2 | 4 | 2 |
4 | 2023-01-01T00:00:00.000Z | 1 | 2 | 2 | 3 |
3 | 2023-01-01T00:00:00.000Z | 1 | 1 | 1 | 4 |
View on DB Fiddle
Удаление дубликатов с помощью ROW_NUMBER
С помощью ROW_NUMBER()
можно избавиться от дубликатов в запросе. Для этого в PARTITION BY
указывают столбцы, по котором необходимо найти уникальность, а также используют подзапрос для фильтрации:
WITH tab AS (
SELECT
sale_date,
row_number() OVER (PARTITION BY sale_date ORDER BY id) AS rn
FROM sales
)
SELECT sale_date FROM tab WHERE rn = 1;
sale_date |
---|
2023-01-01T00:00:00.000Z |
2023-01-02T00:00:00.000Z |
2023-01-03T00:00:00.000Z |
2023-01-04T00:00:00.000Z |
2023-01-05T00:00:00.000Z |
2023-01-06T00:00:00.000Z |
2023-01-07T00:00:00.000Z |
2023-01-08T00:00:00.000Z |
2023-01-09T00:00:00.000Z |
2023-01-10T00:00:00.000Z |
2023-01-11T00:00:00.000Z |
2023-01-12T00:00:00.000Z |
2023-01-13T00:00:00.000Z ... |
View on DB Fiddle
Здесь запрос можно разделить на две логические части. Сперва мы создали группы по дате и пронумеровали строки внутри каждой группы. Затем офильтровали строки, оставив лишь те, что в группе под номером 1. Таким образом, мы избавились от дубликатов.
Выводы
ROW_NUMBER()
- это аналитическая функция в SQL, которая присваивает каждой строке результата запроса уникальный числовой идентификатор. СинтаксисROW_NUMBER()
выглядит примерно так:
ROW_NUMBER() OVER (PARTITION BY column1, column2 ORDER BY column3)
ROW_NUMBER()
начинает с 1 для первой строки каждой группы, увеличиваясь на 1 для каждой следующей строки.ROW_NUMBER()
может быть использован для нумерации строк в результирующем наборе данных, а также для фильтрации и других операций.
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.