Как выбрать n-ую строку в таблице базы данных SQL? - PullRequest
353 голосов
/ 19 августа 2008

Мне интересно изучить некоторые (в идеале) независимые от базы данных способы выбора n -ой строки из таблицы базы данных. Также было бы интересно увидеть, как этого можно достичь, используя встроенную функциональность следующих баз данных:

  • SQL Server
  • MySQL
  • PostgreSQL
  • 1012 * SQLite *
  • Oracle

В настоящее время я делаю что-то вроде следующего в SQL Server 2005, но мне было бы интересно увидеть более независимые подходы других:

WITH Ordered AS (
SELECT ROW_NUMBER() OVER (ORDER BY OrderID) AS RowNumber, OrderID, OrderDate
FROM Orders)
SELECT *
FROM Ordered
WHERE RowNumber = 1000000

Кредит для вышеуказанного SQL: Веблог Firoz Ansari

Обновление: См. Ответ Троэльса Арвина относительно стандарта SQL. Troels, у вас есть ссылки, которые мы можем цитировать?

Ответы [ 29 ]

309 голосов
/ 19 августа 2008

Есть способы сделать это в дополнительных частях стандарта, но многие базы данных поддерживают свой собственный способ сделать это.

Действительно хороший сайт, рассказывающий об этом и других вещах: http://troels.arvin.dk/db/rdbms/#select-limit.

В основном, PostgreSQL и MySQL поддерживают нестандартные:

SELECT...
LIMIT y OFFSET x 

Oracle, DB2 и MSSQL поддерживают стандартные оконные функции:

SELECT * FROM (
  SELECT
    ROW_NUMBER() OVER (ORDER BY key ASC) AS rownumber,
    columns
  FROM tablename
) AS foo
WHERE rownumber <= n

(который я только что скопировал с сайта, указанного выше, поскольку я никогда не использую эти БД)

Обновление: Начиная с PostgreSQL 8.4 поддерживаются стандартные функции управления окнами, поэтому ожидайте, что второй пример будет работать и для PostgreSQL.

Обновление: SQLite добавил поддержку оконных функций в версии 3.25.0 на 2018-09-15, поэтому обе формы также работают в SQLite.

89 голосов
/ 19 августа 2008

Синтаксис LIMIT / OFFSET в PostgreSQL :

SELECT
    *
FROM
    mytable
ORDER BY
    somefield
LIMIT 1 OFFSET 20;

В этом примере выбирается 21-я строка. OFFSET 20 говорит Postgres пропустить первые 20 записей. Если вы не укажете предложение ORDER BY, нет гарантии, какую запись вы получите, что редко бывает полезно.

Очевидно, что стандарт SQL ничего не говорит о предельном ограничении вне сумасшедших оконных функций, поэтому каждый реализует его по-своему.

27 голосов
/ 19 августа 2008

Я не уверен ни в одном из остальных, но я знаю, что SQLite и MySQL не имеют порядка строк по умолчанию. По крайней мере, на этих двух диалектах следующий фрагмент получает 15-ую запись из таблицы, сортируя по дате / времени ее добавления:

SELECT * FROM the_table ORDER BY added DESC LIMIT 1,15

(конечно, вам нужно иметь добавленное поле DATETIME и установить в нем дату / время добавления записи ...)

19 голосов
/ 09 июля 2009

SQL 2005 и выше имеет эту встроенную функцию. Используйте функцию ROW_NUMBER (). Отлично подходит для веб-страниц со стилем просмотра «Предыдущая и Следующая»:

Синтаксис:

SELECT
    *
FROM
    (
        SELECT
            ROW_NUMBER () OVER (ORDER BY MyColumnToOrderBy) AS RowNum,
            *
        FROM
            Table_1
    ) sub
WHERE
    RowNum = 23
16 голосов
/ 19 августа 2008

Я подозреваю, что это крайне неэффективно, но это довольно простой подход, который работал на небольшом наборе данных, на котором я его пробовал.

select top 1 field
from table
where field in (select top 5 field from table order by field asc)
order by field desc

Это позволит получить 5-й элемент, изменить второй верхний номер, чтобы получить другой n-й элемент

Только сервер SQL (я думаю), но он должен работать на более старых версиях, которые не поддерживают ROW_NUMBER ().

12 голосов
/ 16 октября 2014

Проверьте это на SQL Server:

Select top 10 * From emp 
EXCEPT
Select top 9 * From emp

Это даст вам 10-ю строку таблицы emp!

11 голосов
/ 19 августа 2008

1 небольшое изменение: n-1 вместо n.

select *
from thetable
limit n-1, 1
9 голосов
/ 04 сентября 2008

Вопреки тому, что утверждают некоторые из ответов, стандарт SQL не молчит по этому вопросу.

Начиная с SQL: 2003, вы можете использовать «оконные функции» для пропуска строк и ограничения результирующих наборов.

А в SQL: 2008 был добавлен немного более простой подход, использующий <br> OFFSET <em>skip</em> ROWS FETCH FIRST <em>n</em> ROWS ONLY

Лично я не думаю, что добавление SQL: 2008 действительно было необходимо, поэтому, если бы я был ISO, я бы не использовал его в уже достаточно большом стандарте.

6 голосов
/ 19 февраля 2014

SQL SERVER


Выберите n-ю запись сверху

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n

выберите n-ю запись снизу

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID DESC) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n
6 голосов
/ 19 августа 2008

Когда мы работали в MSSQL 2000, мы делали то, что мы называли «трипл-флип»:

EDITED

DECLARE @InnerPageSize int
DECLARE @OuterPageSize int
DECLARE @Count int

SELECT @Count = COUNT(<column>) FROM <TABLE>
SET @InnerPageSize = @PageNum * @PageSize
SET @OuterPageSize = @Count - ((@PageNum - 1) * @PageSize)

IF (@OuterPageSize < 0)
    SET @OuterPageSize = 0
ELSE IF (@OuterPageSize > @PageSize)
    SET @OuterPageSize = @PageSize

DECLARE @sql NVARCHAR(8000)

SET @sql = 'SELECT * FROM
(
    SELECT TOP ' + CAST(@OuterPageSize AS nvarchar(5)) + ' * FROM
    (
        SELECT TOP ' + CAST(@InnerPageSize AS nvarchar(5)) + ' * FROM <TABLE> ORDER BY <column> ASC
    ) AS t1 ORDER BY <column> DESC
) AS t2 ORDER BY <column> ASC'

PRINT @sql
EXECUTE sp_executesql @sql

Это было не элегантно и не быстро, но работало.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...