
- •Простой оператор select
- •Предикаты
- •Предикаты сравнения
- •Предикат in
- •Объединение
- •Пересечение и разность
- •Предикат exists
- •Получение итоговых значений
- •Предложение group by
- •Предложение having
- •Использование в запросе нескольких источников записей
- •Использование ключевых слов some (any) и all с предикатами сравнения
- •Переименование столбцов и вычисления в результирующем наборе
- •Преобразование типов и оператор cast
- •Оператор case
- •Предикат like
- •Предикат like и регулярные выражения
- •Использование значения null в условиях поиска
- •Функция datepart
- •Нумерация строк в соответствии с порядком, заданном значениями первичного ключа
- •Функция row_number
- •Декартово произведение
- •Коррелирующие подзапросы
Нумерация строк в соответствии с порядком, заданном значениями первичного ключа
Естественно, нумероваться строки должны в соответствии с некоторым порядком. Пусть этот порядок задается столбцом первичного ключа, то есть в порядке возрастания (или убывания) значений в этом единственном столбце. Для определенности предположим, что нам нужно перенумеровать модели в таблице Product, где номер модели как раз является первичным ключом. Существенным здесь является то, значения первичного ключа не содержат дубликатов и NULL-значений, в результате чего имеется принципиальная возможность установить однозначное соответствие между номером модели и номером строки в заданном порядке сортировки моделей.
Рассмотрим сначала следующий запрос:
SELECT P1.model, P2.model
FROM Product P1 JOIN
Product P2 ON P1.model <= P2.model
Здесь выполняется соединение двух идентичных таблиц по неравенству P1.model <= P2.model, в результате чего каждая модель из второй таблицы (P2.model) будет соединяться только с теми моделями из первой таблицы (P1.model), номера которых меньше или равны номеру этой модели. В результате получим, например, что модель с минимальным номером (1121) будет присутствовать во втором столбце результирующего набора только один раз, так как она меньше или равна только самой себе. На другом конце будет находиться модель с максимальным номером, так как любая модель будет меньше или равна ей. Следовательно, модель с максимальным номером будет сочетаться с каждой моделью, и число таких сочетаний будет равно общему числу моделей в таблице Product.
Из сказанного выше ясно, что это количество раз, которое каждая из моделей встречается во втором столбце результирующего набора как раз и будет порядковым номером модели при сортировке моделей по возрастанию.
Таким образом, чтобы решить нашу задачу нумерации достаточно пересчитать модели в правом столбце, что нетрудно сделать при помощи группировки и использования агрегатной функции COUNT:
SELECT COUNT(*) no, P2.model
FROM Product P1 JOIN
Product P2 ON P1.model <= P2.model
GROUP BY P2.model
Для нумерации в обратном порядке достаточно поменять знак неравенства на противоположный.
Если ваша СУБД поддерживает ранжирующие функции, то пронумеровать строки можно совсем просто:
SELECT ROW_NUMBER() OVER(ORDER BY model) no, model
FROM Product;
Функция row_number
Функция ROW_NUMBER, как следует из ее названия, нумерует строки, возвращаемые запросом. С ее помощью можно выполнить более сложное упорядочивание строк в отчете, чем то, которое дает предложение ORDER BY в рамках Стандарта SQL-92.
До появления этой функции для нумерации строк, возвращаемых запросом, приходилось использовать довольно сложный интуитивно непонятный алгоритм. Единственным достоинством данного алгоритма является то, что он будет работать практически на всех СУБД, поддерживающих стандарт SQL-92.
Используя функцию ROW_NUMBER можно:
задать нумерацию, которая будет отличаться от порядка сортировки строк результирующего набора;
создать "несквозную" нумерацию, т.е. выделить группы из общего множества строк и пронумеровать их отдельно для каждой группы;
использовать одновмеренно несколько способов нумерации, поскольку, фактически, нумерация не зависит от сортировки строк запроса.
Проще всего возможности функции ROW_NUMBER показать на простых примерах, к чему мы и переходим.
Пример1: Пронумеровать все рейсы из таблицы Trip в порядке возрастания их номеров. Выполнить сортировку по {id_comp, trip_no}.
SELECT row_number() over(ORDER BY trip_no) num,
trip_no, id_comp
FROM trip
WHERE ID_comp < 3
ORDER BY id_comp, trip_no
Предложение OVER, с которым используется функция ROW_NUMBER задает порядок нумерации строк. При этом используется дополнительное предложение ORDER BY, которое не имеет отношения к порядку вывода строк запроса
num |
trip_no |
id_comp |
1 |
1181 |
1 |
2 |
1182 |
1 |
3 |
1187 |
1 |
4 |
1188 |
1 |
5 |
1195 |
1 |
6 |
1196 |
1 |
7 |
1145 |
2 |
8 |
1146 |
2 |
А если требуется пронумеровать рейсы для каждой компании отдельно? Для этого нам потребуется еще одна конструкция в предложении OVER - PARTITION BY.
Конструкция PARTITION BY задает группы строк, для которых выполняется независимая нумерация. Группа определяется равенством значений в списке столбцов, перечисленных в этой конструкции, у строк, составляющих группу.
Пример2: Пронумеровать рейсы каждой компании отдельно в порядке возрастания номеров рейсов.
SELECT row_number() over(partition BY id_comp ORDER BY id_comp,trip_no) num,
trip_no, id_comp
FROM trip
WHERE ID_comp < 3
ORDER BY id_comp, trip_no
num |
trip_no |
id_comp |
1 |
1181 |
1 |
2 |
1182 |
1 |
3 |
1187 |
1 |
4 |
1188 |
1 |
5 |
1195 |
1 |
6 |
1196 |
1 |
1 |
1145 |
2 |
2 |
1146 |
2 |
PARTITION BY id_comp означает, что рейсы каждой компании образуют группу, для которой и выполняется независимая нумерация.
Отсутствие конструкции PARTITION BY, как это быо в первом примере, означает, что все строки результирующего набора образуют одну единственную группу.