sql номер строки в запросе
Функции ранжирования и нумерации в Transact-SQL — ROW_NUMBER, RANK, DENSE_RANK, NTILE
Изучение Transact-SQL продолжается и на очереди у нас функции ранжирования ROW_NUMBER, RANK, DENSE_RANK и NTILE, сейчас мы узнаем, что делают эти функции и зачем вообще они нужны, все как обычно будем рассматривать на примерах.
В языке Transact-SQL очень много различных функций, конструкций, например, PIVOT или INTERSECT, которые в принципе редко используются, их мы даже в нашем мини справочнике Transact-SQL не указывали, но знать, где и как их можно использовать нужно, так же, как и функции ранжирования или их еще называют функции нумерации. Поэтому сегодня давайте поговорим именно об этих функциях, и если говорить конкретно, то это функции: ROW_NUMBER, RANK, DENSE_RANK, NTILE.
И начнем мы, конечно же, с определения, что же вообще это за ранжирующие функции.
Ранжирующие функции в T-SQL
Ранжирующие функции — это функции, которые возвращают значение для каждой строки группы в результирующем наборе данных. На практике они могут быть использованы, например, для простой нумерации списка, составления рейтинга или постраничной выборки.
И для того чтобы лучше усвоить работу и применение этих функций, давайте рассмотрим все их по очереди, и параллельно будем сравнивать их друг с другом, т.е. таким образом, мы еще и узнаем в чем их отличие. Но для того чтобы начать рассматривать примеры, необходимо определится с исходными данными.
Заметка! Для комплексного изучения языка SQL рекомендую почитать мою книгу «SQL код». Данный книга рассчитана на изучение языка SQL как стандарта, т.е. на изучение тех возможностей SQL, которые доступны и точно будут работать во всех популярных системах управления базами данных (СУБД).
Исходные данные для примеров
Использовать мы будем MS SQL Server Express 2014, а запросы будем писать в Management Studio Express. В качестве тестовых данных будем использовать таблицу selling, которая будет содержать различные товары (телефоны, планшеты, ноутбуки, программы) с выдуманными ценами.
Наша тестовая таблица
Заполним ее тестовыми данными, в итоге получим следующее (для выборки пишем простой запрос select)
ROW_NUMBER
ROW_NUMBER – функция нумерации в Transact-SQL, которая возвращает просто номер строки.
ROW_NUMBER () OVER ([PARTITION BY столбы группировки] ORDER BY столбец сортировки)
где, partition by — это не обязательное ключевое слово, после которого указывается столбец или столбцы, по которым группировать данные, а order by столбец для сортировки, т.е. по данному столбцу будут отсортированы данные, а потом пронумерованы, он уже обязателен. Сразу скажу, чтобы не возвращаться, что эти ключевые слова относятся ко всем функциям ранжирования, которые мы будем сегодня использовать.
Пример без группировки с сортировкой по цене
Пример с группировкой по категории и с сортировкой по цене
Как видите, здесь уже нумерация идет в каждой категории.
RANK – ранжирующая функция, которая возвращает ранг каждой строки. В данном случае, в отличие от row_number(), идет уже анализ значений и в случае нахождения одинаковых, функция возвращает одинаковый ранг с пропуском следующего. Как было уже сказано выше, здесь также можно использовать partition by для группировки и обязательно нужно указывать столбец сортировки в order by.
Пример без группировки с сортировкой по цене и отличие от row_number()
Пример с группировкой по категории и с сортировкой по цене и отличие от row_number()
DENSE_RANK
DENSE_RANK — ранжирующая функция, которая возвращает ранг каждой строки, но в отличие от rank, в случае нахождения одинаковых значений, возвращает ранг без пропуска следующего.
Пример без группировки с сортировкой по цене и отличие от rank() и row_number()
NTILE
NTILE – функция Transact-SQL, которая делит результирующий набор на группы по определенному столбцу. Количество групп указывается в качестве параметра. В случае если в группах получается не одинаковое количество строк, то в первой группе будет наибольшее количество, например, в нашем случае строк 10 и если мы поделим на три группы, то в первой будет 4 строки, а во второй и третей по 3.
В заключение давайте приведем пример, в котором мы наглядно увидим различия в работе всех функций, например, вот такой
Заметка! Для комплексного изучения языка T-SQL рекомендую посмотреть мои видеокурсы по T-SQL, в которых используется последовательная методика обучения и рассматриваются все конструкции языка SQL и T-SQL.
На этом я думаю по ранжирующим функциям достаточно, в следующих статьях мы продолжим изучение Transact-SQL, а на этом пока все. Удачи!
MySQL номер строки
Поставим задачу: необходимо вывести имя пользователя, количество его очков и место в рейтинге по количеству этих очков. Т.е. такую таблицу:
RANK | POINTS | NAME |
1 | 500 | Алексей |
2 | 300 | Сергей |
3 | 200 | Виталий |
Получать данные будем из таблицы истории получения очков, которая зовётся «history». Выглядит она так:
DATE | POINTS | NAME |
26.03.2017 | 300 | Алексей |
16.08.2016 | 200 | Алексей |
11.01.2016 | 200 | Виталий |
28.12.2015 | 200 | Сергей |
14.07.2015 | 100 | Сергей |
Для начала получим суммы набранных очков, сгруппированные по именам пользователей и отсортированные по убыванию. Запрос будет выглядеть так:
SELECT SUM(POINTS) as ‘POINTS’, NAME FROM `history` GROUP BY NAME ORDER BY SUM(POINTS) DESC;
База вернёт следующую таблицу:
POINTS | NAME |
500 | Алексей |
300 | Сергей |
200 | Виталий |
Нумеровка делается через переменную, добавляемую к выводу. Казалось бы, можно сделать всё просто:
SELECT @rank:=@rank+1 AS ‘RANK’, SELECT SUM(POINTS) as ‘POINTS’, NAME FROM `history` GROUP BY NAME ORDER BY SUM(POINTS) DESC;
Но если сделать такой запрос, то результат будет плачевным. Назначение рейтинга произойдёт после группировки, но до сортировки ORDER BY SUM(POINTS). Выглядеть результат будет так:
RANK | POINTS | NAME |
1 | 500 | Алексей |
3 | 300 | Сергей |
2 | 200 | Виталий |
Цифры ранга идут не по порядку: 1, 3, 2. Чтобы исправить положение необходимо добавлять столбец ранга после группировки и сортировки, в отдельном запросе. По логике, получается SELECT в SELECT. Синтаксис будет такой:
SET @rank=0;
SELECT @rank:=@rank+1 AS ‘RANK’, POINTS, NAME FROM
(
SELECT SUM(POINTS) as ‘POINTS’, NAME
FROM `history` GROUP BY NAME ORDER BY SUM(POINTS) DESC
Обратите внимание на окончание запроса. Без «as t;» написать запрос нельзя, иначе будет ошибка «Every derived table must have its own alias!«.
Результат такого запроса будет выглядеть как нормальная ранговая таблица. С правильным расположением цифр ранга:
RANK | POINTS | NAME |
1 | 500 | Алексей |
2 | 300 | Сергей |
3 | 200 | Виталий |
Теперь усложним задачу. Получим содержание одной ячейки такой таблицы.
SELECT @rank:=@rank+1 AS ‘RANK’, NAME FROM
(
SELECT SUM(POINTS), NAME
FROM `history` GROUP BY NAME ORDER BY SUM(POINTS) DESC
) as t2
WHERE NAME = ‘Виталий’;
Обратите внимание на хвосты: «as t1», «as t2». Нужны разные псевдонимы, иначе будет ошибка «Every derived table must have its own alias!«.
Конечно же, на реальном проекте такая таблица будет содержать id пользователя, а не его имя. Потому что в строке правды нет, а в числе есть 🙂
Функция ROW_NUMBER стр. 2
В MySQL ранжирующих/оконных функций не было до версии 8.0, однако была возможность использовать переменные непосредственно в запросе SQL. В частности, с помощью переменных можно решить задачу нумерации строк запроса. Продемонстрируем это на примере, который рассматривался на предыдущей странице.
|
В третьей строке запроса выполняется инициализация переменной и присваивается ей начальное значение. В итоге каждая строка таблицы Trip будет соединяться со строкой из одного столбца, содержащего 0 (просто декартово произведение).
В первой строке запроса значение переменной инкрементируется на 1, что происходит при вычислении каждой следующей строки в порядке, заданном предложением ORDER BY. В итоге мы получаем нумерацию строк в порядке сортировки.
Если вы опустите инициализацию переменной, то можете получить правильный результат. Но это не гарантировано, в чем можно убедиться, повторно выполнив этот же запрос в текущей сессии соединения с базой данных. Вы должны получить продолжение нумерации с максимального значения переменной @i, достигнутого на предыдущем запуске скрипта.
Мы также можем перенумеровать строки для каждой компании отдельно, т.е. сымитировав поведение PARTITION BY в запросе
Идея решения состоит в следующем. Введем еще одну переменную для хранения номера компании. При инициализации присвоим ей несуществующий номер (например, 0). Затем для каждой строки будем проверять, совпадает ли номер с номером компании текущей строки. Если значения совпадают, будем инкрементировать, если нет, сбрасывать в 1. Наконец, будем присваивать переменной номер компании из текущей строки. Дело в том, что проверка выполняется до присвоения, тем самым мы сравниваем текущее значение номера компании с номером компании из предыдущей строки (в заданном порядке сортировки). Теперь сам запрос.
|
Проверить эти запросы вы можете из консоли, выбрав из списка MySQL.
Эмуляция функции row_number() в MySQL
Нумерация строк
Чтобы пронумеровать строки, мы должны объявить переменную запроса. Продемонстрируем этот подход на примере простой таблицы, содержащей список работников предприятия ( employees ). Следующий запрос выбирает 5 работников из таблицы, присваивая им номера по порядку, начиная с 1:
В выше приведённом запросе мы:
Другая техника, позволяющая достичь того же результата, заключается в создании вместо глобальной переменной производной таблицы и перекрёстном объединении этих двух таблиц. Пример такого запроса:
Обратите внимание на то, что для соблюдения правил синтаксиса у производной таблицы должен быть псевдоним.
Возобновление нумерации в группах
Нам нужно сформировать список платежей, в котором каждому платежу будет соответствовать определённый порядковый номер. Для того чтобы получить требуемый результат, нам понадобятся две переменные: одна – с порядковым номером строки, другая – для хранения идентификатора клиента из предыдущей строки, чтобы сравнить его с текущим. Наш запрос будет выглядеть так:
Мы использовали оператор CASE для вычисления условия: если номер клиента остаётся прежним, мы увеличиваем номер строки на 1, в противном случае мы устанавливаем номер строки равным 1. Результат будет тем же, что и на выше приведённом скриншоте.
Теперь добьёмся того же результата, используя технику производной таблицы и перекрёстного запроса:
Как включить нумерацию строк кода в SQL Server Management Studio
Всем привет! Сегодня я расскажу о том, как включить нумерацию строк кода в среде SQL Server Management Studio, иными словами, как отобразить номер строки в редакторе SQL запросов SSMS.
Для чего это может потребоваться
При работе с большими SQL инструкциями или хранимыми процедурами, которые содержат много строк кода, достаточно полезно и очень удобно знать номера строк в редакторе запросов. Ведь благодаря этому мы легко и, главное, быстро можем переместиться к нужному нам участку кода, например, в тех случаях когда Microsoft SQL Server выдает нам сообщение об ошибке в процессе выполнения той или иной инструкции, при этом из текста сообщения иногда бывает не понятно, где именно возникла ошибка, но кроме описания ошибки в сообщении обычно указывается еще и точное местонахождение этой ошибки, т.е. номер конкретной строки.
В этом примере ошибка возникла на строке 40.
А по умолчанию отображение номера строки в SSMS отключено, поэтому чтобы не тратить время на поиск ошибки, визуально выискивая, где же эта ошибка возникла, мы можем включить нумерацию строк кода и быстро переходить к нужному нам участку.
Пример без нумерации строк кода
С нумерацией строк кода
Включение отображения номера строки в редакторе SQL запросов SSMS
В результате в редакторе SQL запросов все строки будут пронумерованы.
На сегодня это все, надеюсь, материал был Вам полезен, пока!