Как выбрать N-ю строку в таблице базы данных SQL?



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




  • SQL Server

  • MySQL

  • PostgreSQL

  • SQLite

  • Оракул


в настоящее время я делаю что-то вроде следующего в 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 Ансари блог



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

3081   29  

29 ответов:

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

действительно хороший сайт, который говорит об этом и других вещах 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

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

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

The LIMIT/OFFSET синтаксис в PostgreSQL - это:

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

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

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

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

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

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

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

синтаксис:

SELECT
    *
FROM
    (
        SELECT
            ROW_NUMBER () OVER (ORDER BY MyColumnToOrderBy) AS RowNum,
            *
        FROM
            Table_1
    ) sub
WHERE
    RowNum = 23

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

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 server (я думаю), но должен работать на более старых версиях, которые не поддерживают ROW_NUMBER ().

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

select *
from thetable
limit n-1, 1

проверьте его на SQL Server:

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

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

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

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

и в SQL: 2008 был добавлен несколько более простой подход, используя
OFFSET skip ROWS FETCH FIRST n ROWS ONLY

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

Oracle:

select * from (select foo from bar order by foo) where ROWNUM = x

когда мы работали в MSSQL 2000, мы делали то, что мы называли "тройной флип":

редактировать

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

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

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

вот быстрое решение вашей путаницы.

SELECT * FROM table ORDER BY `id` DESC LIMIT N, 1

Это очень распространенный вопрос во время интервью, и это очень простой ответ на него.

далее, если вам нужна сумма, идентификатор или какой-то числовой порядок сортировки, чем u может пойти для функции CAST в MySQL.

SELECT DISTINCT (`amount`) FROM cart ORDER BY CAST( `amount` AS SIGNED ) DESC LIMIT 4 , 1

здесь, заполнив N = 4, Вы сможете получить пятую последнюю запись Самая высокая сумма из таблицы корзины. Вы можете подогнать свое поле и имя таблицы и придумать решение.

добавить:

LIMIT n,1

это ограничит результаты одним результатом, начиная с результата n.

ограничение n, 1 не работает в MS SQL Server. Я думаю, что это единственная крупная база данных, которая не поддерживает этот синтаксис. Справедливости ради, это не является частью стандарта SQL, хотя он настолько широко поддерживается, что он должен быть. Во всем, кроме SQL server LIMIT отлично работает. Для SQL server я не смог найти элегантное решение.

вот общая версия sproc, которую я недавно написал для Oracle, которая позволяет динамическую подкачку / сортировку-HTH

-- p_LowerBound = first row # in the returned set; if second page of 10 rows,
--                this would be 11 (-1 for unbounded/not set)
-- p_UpperBound = last row # in the returned set; if second page of 10 rows,
--                this would be 20 (-1 for unbounded/not set)

OPEN o_Cursor FOR
SELECT * FROM (
SELECT
    Column1,
    Column2
    rownum AS rn
FROM
(
    SELECT
        tbl.Column1,
        tbl.column2
    FROM MyTable tbl
    WHERE
        tbl.Column1 = p_PKParam OR
        tbl.Column1 = -1
    ORDER BY
        DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 1, Column1, 'X'),'X'),
        DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 1, Column1, 'X'),'X') DESC,
        DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate),
        DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate) DESC
))
WHERE
    (rn >= p_lowerBound OR p_lowerBound = -1) AND
    (rn <= p_upperBound OR p_upperBound = -1);

но на самом деле, разве все это не просто салонные трюки для хорошего дизайна базы данных в первую очередь? Несколько раз мне нужна была такая функциональность, как это было для простого запроса, чтобы сделать быстрый отчет. Для любой реальной работы, используя трюки, как эти приглашает неприятности. Если выбор конкретной строки необходим, то просто иметь столбец с последовательным значением и сделать с ним.

например, если вы хотите выбрать каждую 10-ю строку в MSSQL, вы можете использовать;

SELECT * FROM (
  SELECT
    ROW_NUMBER() OVER (ORDER BY ColumnName1 ASC) AS rownumber, ColumnName1, ColumnName2
  FROM TableName
) AS foo
WHERE rownumber % 10 = 0

просто возьмите мод и изменить номер 10 здесь любое число, которое вы хотите.

в Sybase SQL Anywhere:

SELECT TOP 1 START AT n * from table ORDER BY whatever

Не забывайте порядок ПО или это бессмысленно.

для SQL Server общий способ перейти по номеру строки как таковой: Установите ROWCOUNT @row --@row = номер строки, над которой вы хотите работать.

Например:

set rowcount 20 --устанавливает строку в 20-ю строку

выберите мясо, сыр из dbo.сэндвич --выберите столбцы из таблицы в 20-й строке

задать количество строк 0-задает количество строк для всех строк

это вернет информацию 20-й строки. Будьте уверены, чтобы поставить в параметр rowcount 0 потом.

Я знаю noobish, но я SQL noob, и я использовал его, так что я могу сказать?

T-SQL-выбор N-го номера записи из таблицы

select * from
 (select row_number() over (order by Rand() desc) as Rno,* from TableName) T where T.Rno = RecordNumber

Where  RecordNumber --> Record Number to Select
       TableName --> To be Replaced with your Table Name

например, чтобы выбрать 5-ю запись из таблицы сотрудника, ваш запрос должен быть

select * from
 (select row_number() over (order by Rand() desc) as Rno,* from Employee) T where T.Rno = 5
SELECT * FROM emp a
WHERE  n = (SELECT COUNT( _rowid)
              FROM emp b
             WHERE a. _rowid >= b. _rowid);
SELECT
    top 1 *
FROM
    table_name
WHERE
    column_name IN (
        SELECT
            top N column_name
        FROM
            TABLE
        ORDER BY
            column_name
    )
ORDER BY
    column_name DESC

Я написал этот запрос для поиска N-й строки. Пример с этим запросом будет

SELECT
    top 1 *
FROM
    Employee
WHERE
    emp_id IN (
        SELECT
            top 7 emp_id
        FROM
            Employee
        ORDER BY
            emp_id
    )
ORDER BY
    emp_id DESC

невероятно, что вы можете найти SQL-движок, выполняющий этот...

WITH sentence AS
(SELECT 
    stuff,
    row = ROW_NUMBER() OVER (ORDER BY Id)
FROM 
    SentenceType
    )
SELECT
    sen.stuff
FROM sentence sen
WHERE sen.row = (ABS(CHECKSUM(NEWID())) % 100) + 1

ничего особенного, никаких специальных функций, если вы используете Caché, как я...

SELECT TOP 1 * FROM (
  SELECT TOP n * FROM <table>
  ORDER BY ID Desc
)
ORDER BY ID ASC

учитывая, что у вас есть столбец ID или столбец datestamp, которому вы можете доверять.

вот как я бы сделал это в DB2 SQL, я считаю, что RRN (относительный номер записи) хранится в таблице O / S;

SELECT * FROM (                        
   SELECT RRN(FOO) AS RRN, FOO.*
   FROM FOO                         
   ORDER BY RRN(FOO)) BAR             
 WHERE BAR.RRN = recordnumber
select * from 
(select * from ordered order by order_id limit 100) x order by 
x.order_id desc limit 1;

Сначала выберите верхние 100 строк, упорядочив их по возрастанию, а затем выберите последнюю строку, упорядочив ее по убыванию и ограничьте до 1. Однако это очень дорогое заявление, поскольку оно дважды обращается к данным.

Мне кажется, что для эффективности вам нужно 1) сгенерировать случайное число между 0 и одним меньше, чем количество записей базы данных, и 2) иметь возможность выбрать строку в этой позиции. К сожалению, разные базы данных имеют разные генераторы случайных чисел и разные способы выбора строки в позиции в результирующем наборе - обычно вы указываете, сколько строк пропустить и сколько строк вы хотите, но это делается по-разному для разных баз данных. Вот то, что работает для меня в SQLite:

select * 
from Table 
limit abs(random()) % (select count(*) from Words), 1;

Это зависит от возможности использовать подзапрос в предложении limit (который в SQLite является LIMIT ,) выбор количества записей в таблице должен быть особенно эффективным, являясь частью метаданных базы данных, но это зависит от реализации базы данных. Кроме того, я не знаю, действительно ли запрос построит результирующий набор перед получением N-й записи, но я надеюсь, что это не нужно. Обратите внимание, что я не указание предложения "order by". Возможно, лучше "заказать" что - то вроде первичного ключа, который будет иметь индекс-получение N-й записи из индекса может быть быстрее, если база данных не может получить N-ю запись из самой базы данных без построения результирующего набора.

в Oracle 12c, вы можете использовать С ORDER BY

например, чтобы получить 3-ю запись сверху:

SELECT * 
FROM   sometable
ORDER BY column_name
OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY;

для SQL server следующая строка возвращает первую строку из таблицы giving.

declare @rowNumber int = 1;
    select TOP(@rowNumber) * from [dbo].[someTable];
EXCEPT
    select TOP(@rowNumber - 1) * from [dbo].[someTable];

вы можете перебирать значения с помощью чего-то вроде этого:

WHILE @constVar > 0
BEGIN
    declare @rowNumber int = @consVar;
       select TOP(@rowNumber) * from [dbo].[someTable];
    EXCEPT
       select TOP(@rowNumber - 1) * from [dbo].[someTable];  

       SET @constVar = @constVar - 1;    
END;

Comments

    Ничего не найдено.