Урок 5. Ограничение и смещение
Кроме фильтров и сортировок, в SELECT-запросах можно также ограничивать выборку. Например, когда вам нужные не все данные, а скажем только первые 10 строк. Для этого существует конструкция LIMIT.
Работать в этом уроке будем с такой таблицей:
| id | name | count | price | country |
|---|---|---|---|---|
| 1 | Телевизор | 3 | 43200.00 | RU |
| 2 | Микроволновая печь | 4 | 3200.00 | UA |
| 3 | Холодильник | 3 | 12000.00 | RU |
| 4 | Роутер | 1 | 1340.00 | US |
| 5 | Компьютер | 0 | 26150.00 | RU |
| 6 | Холодильник 2 | 2 | 14390.00 | BL |
| 7 | Чайник | 8 | 1200.00 | RU |
| 8 | Дрон | 1 | 45990.00 | CH |
| 9 | Вентилятор | 3 | 3000.00 | RU |
Давайте попробуем вывести 5 самых дорогих товаров. Сперва напишем базовый SQL-запрос:
SELECT * FROM products ORDER BY price DESC
И с помощью данного запроса мы получим все товары, отсортированные по цене в обратном порядке — ORDER BY price DESC. То есть дорогие товары будут сверху:
| id | name | count | price | country |
|---|---|---|---|---|
| 8 | Дрон | 1 | 45990.00 | CH |
| 1 | Телевизор | 3 | 43200.00 | RU |
| 5 | Компьютер | 0 | 26150.00 | RU |
| 6 | Холодильник 2 | 2 | 14390.00 | BL |
| 3 | Холодильник | 3 | 12000.00 | RU |
| 2 | Микроволновая печь | 4 | 3200.00 | UA |
| 9 | Вентилятор | 3 | 3000.00 | RU |
| 4 | Роутер | 1 | 1340.00 | US |
| 7 | Чайник | 8 | 1200.00 | RU |
Теперь, если я оставлю верхние 5 записей, то как раз и получу 5 самых дорогих товаров:
SELECT * FROM products ORDER BY price DESC LIMIT 5
И LIMIT 5 как раз и говорит базе, что нам нужны только 5 первых (верхних) записей. После выполнения запроса мы получим такую таблицу:
| id | name | count | price | country |
|---|---|---|---|---|
| 8 | Дрон | 1 | 45990.00 | CH |
| 1 | Телевизор | 3 | 43200.00 | RU |
| 5 | Компьютер | 0 | 26150.00 | RU |
| 6 | Холодильник 2 | 2 | 14390.00 | BL |
| 3 | Холодильник | 3 | 12000.00 | RU |
Теперь давайте получим 5 самых дорогих товаров, которые есть на складе. Для этого нужно написать такой SQL-запрос:
SELECT * FROM products WHERE count > 0 ORDER BY price DESC LIMIT 5
После его выполнения выдача немного изменится, так как товары которые закончились в итоговую таблицу не попадают:
| id | name | count | price | country |
|---|---|---|---|---|
| 8 | Дрон | 1 | 45990.00 | CH |
| 1 | Телевизор | 3 | 43200.00 | RU |
| 6 | Холодильник 2 | 2 | 14390.00 | BL |
| 3 | Холодильник | 3 | 12000.00 | RU |
| 2 | Микроволновая печь | 4 | 3200.00 | UA |
Обратите внимание на порядок следования блоков запроса:
1. Сперва идет SELECT FROM — выбрать ИЗ;
2. Затем блок условия WHERE;
3. После сортировка ORDER BY;
4. И завершает ограничение LIMIT.
Первый блок SELECT FROM обязательный, так как он говорит, что мы хотим сделать.
Остальные блоки опциональны. То есть мы можем убрать любой из них, главное, чтобы сохранялся порядок: (1) WHERE (2) ORDER BY (3) LIMIT.
Смещение с помощью OFFSET
Но вернемся снова к LIMIT. И помимо ограничения выборки, мы также можем делать смещение. Например, искать не первые 5 самых дорогих товаров, а следующую пятерку.
Для этого после LIMIT нужно добавить блок OFFSET:
SELECT * FROM products WHERE count > 0 ORDER BY price DESC LIMIT 5 OFFSET 5
И собственно конструкция OFFSET указывает на то, сколько записей нужно пропустить. После запуска мы получим 3 товара, так как изначально в таблице у нас 8 товаров, из которых 5 мы пропускаем с помощью OFFSET, а затем с помощью LIMIT выводим еще 5, но так как после пропуска остается всего 3 товара, то их мы и видим:
| id | name | count | price | country |
|---|---|---|---|---|
| 6 | Холодильник 2 | 2 | 14390.00 | BL |
| 3 | Холодильник | 3 | 12000.00 | RU |
| 2 | Микроволновая печь | 4 | 3200.00 | UA |
Постраничный просмотр
Благодаря этой особенности, с помощью LIMIT и OFFSET можно организовывать постраничный просмотр информации. Например, нам нужно выводить по два товара на странице, скажем на каком сайте или в программе.
Тогда в LIMIT мы прописываем двойку, а для OFFSET изначально ставим 0:
SELECT * FROM products WHERE count > 0 ORDER BY price DESC LIMIT 2 OFFSET 0
После запуска SQL-запроса мы увидим два самых дорогих товара, которые будут отображаться на первой странице:
| id | name | count | price | country |
|---|---|---|---|---|
| 8 | Дрон | 1 | 45990.00 | CH |
| 1 | Телевизор | 3 | 43200.00 | RU |
Далее нам нужно получить следующую пару. Для этого делаем пропуск первых двух товаров:
SELECT * FROM products WHERE count > 0 ORDER BY price DESC LIMIT 2 OFFSET 2
| id | name | count | price | country |
|---|---|---|---|---|
| 5 | Компьютер | 0 | 26150.00 | RU |
| 6 | Холодильник 2 | 2 | 14390.00 | BL |
Теперь получим товары на третьей странице и для этого мы можем воспользоваться вот такой формулой:
(P — 1) x N, где P — это номер страницы, которая нам нужна, а N – это количество товаров, которые мы выводим на странице.
Значение N у нас фиксировано и указывается в блоке LIMIT. То есть сейчас это 2.
Значение P мы выбираем из набора целых чисел: 1, 2, 3 и тд.
Результат вычисления мы подставляем в блок OFFSET.
Сейчас мы делаем расчеты для третьей страницы, поэтому получаем:
(P — 1) x N = (3 — 1) x 2 = 4
Ставим четверку в OFFSET и получаем финальный SQL-запрос:
SELECT * FROM products WHERE count > 0 ORDER BY price DESC LIMIT 2 OFFSET 4
Который вернет следующую таблицу:
| id | name | count | price | country |
|---|---|---|---|---|
| 5 | Компьютер | 0 | 26150.00 | RU |
| 6 | Холодильник 2 | 2 | 14390.00 | BL |
С основой мы закончили, но хочу отметить одну особенность конструкции OFFSET, а именно то, что OFFSET в MySQL является частью LIMIT.
То есть мы можем использовать или чистый LIMIT, или LIMIT в паре с OFFSET, но не можем использовать OFFSET сам по себе, так как это будет синтаксической ошибкой.
Также мы не можем менять LIMIT и OFFSET местами.
Что ж, на этом с базовыми возможностями ограничений и смещений мы заканчиваем, а в следующем уроке рассмотрим особенности применения LIMIT и OFFSET в PostgreSQL, MS SQLServer, Oracle и SQLite.
Следующий урок
Урок 6. TOP, LIMIT, FETCH и OFFSET в других базах
Изучаем особенности использования TOP, LIMIT, FETCH и OFFSET в PostgreSQL, MS SQLServer, Oracle и SQLite.
Полный курс с практикой
- 57 уроков
- 261 задание
- Сертификат
- Поддержка преподавателя
- Доступ к курсу навсегда
- Можно в рассрочку
SUBSTRING (Transact-SQL)
Возвращает часть символьного, двоичного, текстового или графического выражения в SQL Server.
Синтаксис
SUBSTRING ( expression, start, length )
Сведения о синтаксисе Transact-SQL для SQL Server 2014 (12.x) и более ранних версиях см . в документации по предыдущим версиям.
Аргументы
выражение
Выражение типа character, binary, text, ntext или image.
Начало
Целое число или выражение типа bigint, указывающее начальную позицию возвращаемых символов. (Нумерация начинается с 1, то есть первый символ в выражении имеет позицию 1.) Если аргумент start имеет значение меньше 1, то возвращаемое выражение начинается с первого символа, который указан в аргументе expression. В этом случае количество возвращаемых символов является наибольшим значением либо суммы start + length– 1, либо 0. Если значение start больше количества символов в выражении значения, возвращается выражение нулевой длины.
length
Положительное целое число или выражение типа bigint, указывающее количество символов выражения expression, которое будет возвращено. Если значение length отрицательно, возникает ошибка и выполнение инструкции прерывается. Если сумма start и length больше количества символов в expression, то возвращается целочисленное выражение значения, начинающееся со значения start.
Типы возвращаемых данных
Возвращает символьные данные, если expression имеет один из поддерживаемых символьных типов данных. Возвращает двоичные данные, если аргумент expression имеет один из поддерживаемых двоичных типов данных. Возвращенная строка имеет тот же самый тип, как и заданное выражение. Исключения указаны в таблице.
| Заданное выражение | Возвращаемый тип |
|---|---|
| char/varchar/text | varchar |
| nchar/nvarchar/ntext | nvarchar |
| binary/varbinary/image | varbinary |
Замечания
Значения start и length должны быть указаны в виде количества символов для типов данных ntext, char или varchar и байтов для типов данных text, image, binary или varbinary.
Аргумент expression должен иметь тип varchar(max) или varbinary(max), если аргумент start или length содержит значение, превышающее 2 147 483 647.
Дополнительные символы (суррогатные пары)
При использовании параметров сортировки дополнительных символов (SC) и start, и length обрабатывают каждую суррогатную пару в expression как один символ. Дополнительные сведения см. в статье Collation and Unicode Support.
Примеры
А. Использование SUBSTRING с символьной строкой
Следующий пример показывает, как получить часть символьной строки. Из таблицы sys.databases этот запрос возвращает имена системных баз данных в первом столбце, первую букву имени базы данных во втором столбце и третий и четвертый символы в последнем столбце.
SELECT name, SUBSTRING(name, 1, 1) AS Initial , SUBSTRING(name, 3, 2) AS ThirdAndFourthCharacters FROM sys.databases WHERE database_id < 5;
| name | Начальное | ThirdAndFourthCharacters |
|---|---|---|
| master | m | st |
| tempdb | t | mp |
| модель | m | de |
| msdb | m | db |
Далее показано, как можно вывести второй, третий и четвертый символ строковой константы abcdef .
SELECT x = SUBSTRING('abcdef', 2, 3);
x ---------- bcd (1 row(s) affected)
B. Использование SUBSTRING с данными типа text, ntext или image
Для выполнения приведенных ниже примеров необходимо установить базу данных pubs.
В приведенном ниже примере показано, как вернуть первые 10 символов из каждого столбца данных text и image в таблице pub_info базы данных pubs . Данные text возвращаются как varchar, а данные image — как varbinary.
USE pubs; SELECT pub_id, SUBSTRING(logo, 1, 10) AS logo, SUBSTRING(pr_info, 1, 10) AS pr_info FROM pub_info WHERE pub_id = '1756';
pub_id logo pr_info ------ ---------------------- ---------- 1756 0x474946383961E3002500 This is sa (1 row(s) affected)
В приведенном ниже примере показано влияние функции SUBSTRING на данные типов text и ntext. Во-первых, пример создает новую таблицу в базе данных pubs под именем npub_info . Во-вторых, пример создает столбец pr_info в таблице npub_info из первых 80 символов столбца pub_info.pr_info и добавляет ü в качестве первого символа. Наконец, с помощью предложения INNER JOIN извлекаются все идентификационные номера издателей, а также обработанные функцией SUBSTRING значения столбцов типа text и ntext со сведениями об издателях.
IF EXISTS (SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_name = 'npub_info') DROP TABLE npub_info; GO -- Create npub_info table in pubs database. Borrowed from instpubs.sql. USE pubs; GO CREATE TABLE npub_info ( pub_id CHAR(4) NOT NULL REFERENCES publishers(pub_id) CONSTRAINT UPKCL_npubinfo PRIMARY KEY CLUSTERED, pr_info ntext NULL ); GO -- Fill the pr_info column in npub_info with international data. RAISERROR('Now at the inserts to pub_info. ',0,1); GO INSERT npub_info VALUES('0736', N'üThis is sample text data for New Moon Books, publisher 0736 in the pubs database') ,('0877', N'üThis is sample text data for Binnet & Hardley, publisher 0877 in the pubs databa') ,('1389', N'üThis is sample text data for Algodata Infosystems, publisher 1389 in the pubs da') ,('9952', N'üThis is sample text data for Scootney Books, publisher 9952 in the pubs database') ,('1622', N'üThis is sample text data for Five Lakes Publishing, publisher 1622 in the pubs d') ,('1756', N'üThis is sample text data for Ramona Publishers, publisher 1756 in the pubs datab') ,('9901', N'üThis is sample text data for GGG&G, publisher 9901 in the pubs database. GGG&G i') ,('9999', N'üThis is sample text data for Lucerne Publishing, publisher 9999 in the pubs data'); GO -- Join between npub_info and pub_info on pub_id. SELECT pr.pub_id, SUBSTRING(pr.pr_info, 1, 35) AS pr_info, SUBSTRING(npr.pr_info, 1, 35) AS npr_info FROM pub_info pr INNER JOIN npub_info npr ON pr.pub_id = npr.pub_id ORDER BY pr.pub_id ASC;
Примеры: Azure Synapse Analytics и система платформы аналитики (PDW)
C. Использование SUBSTRING с символьной строкой
Следующий пример показывает, как получить часть символьной строки. Из таблицы dbo.DimEmployee данный запрос возвращает фамилию в одном столбце и первую букву имени в другом.
-- Uses AdventureWorks SELECT LastName, SUBSTRING(FirstName, 1, 1) AS Initial FROM dbo.DimEmployee WHERE LastName LIKE 'Bar%' ORDER BY LastName;
LastName Initial -------------------- ------- Barbariol A Barber D Barreto de Mattos P
В приведенном ниже примере показано, как получить второй, третий и четвертый символы строковой константы abcdef .
USE ssawPDW; SELECT TOP 1 SUBSTRING('abcdef', 2, 3) AS x FROM dbo.DimCustomer;
x ----- bcd
Как вывести определенное количество строк sql
Для выборки определённого количества строк из таблицы в SQL используют оператор LIMIT .
Например, запрос приведённый ниже вернёт первые 100 записей из таблицы topics.
SELECT * FROM topics LIMIT 100;
Если же мы хотим пропустить какое-то количество записей и затем взять определённое количество, в связке с LIMIT используется еще и OFFSET .
SELECT * FROM topics LIMIT 100 OFFSET 20;
С помощью запроса выше мы получим 100 записей из таблицы topics, но при этом пропустим первые 20 строк.
Как вывести первую строку в запросе sql
(4) какая разница где писать?
Как ограничить выводимое число записей, или
есть ли в InterBase и Firebird аналог limit, top и т.п. ?
Да, есть.
Начиная с InterBase 6.5 эта и последующие версии InterBase поддерживают синтаксис ROWS.
SELECT * FROM TABLE
ORDER BY
[ROWS [TO ] [BY ] [PERCENT] [WITH TIES]
Подробнее см. документацию.
Начиная с Firebird 1.0 эта и последующие версии Firebird поддерживают синтаксис first/skip
SELECT first x skip y * FROM TABLE
Подробнее см. ReleaseNotes. В Firebird 2.0 также будет поддерживаться синтаксис ROWS, совместимый с InterBase.
Оба "ограничителя" количества записей ROWS и first/skip работают следующим образом:
сервер выполняет запрос
на этапе передачи данных клиенту сервер пропускает skip/to записей, и после выдачи first/rows записей выдает клиенту сигнал eof.
то есть, в случае обработки записей на сервере (order by без индекса, group by без индекса, выборка из процедуры и т.п.) сервер все равно сначала выполнит запрос целиком, и только после этого выдаст клиентской части запрошенное число записей. В обоих случаях указание rows/to или first/skip не имеет смысла без ORDER BY ("первые" записи из несортированного набора будут совершенно случайными), хотя Firebird поддерживает возможность в подзапросах указывать first/skip.
Примеры: выбрать 5 записей пропустив 10 из таблицы employee, упорядоченной по фамилии сотрудников:
select first 5 skip 10 *
from employee
order by last_name
select * from employee
order by last_name
rows 5 to 10
это для интербэйса
Immortal спасибо. rows 1 to 3 заработал.
А вообще я непонял почему в ibexpert так криво сделали гады. Столкнулся с этим говном потому что в институте учат на ibexpert