Вопрос

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

  • SQL-сервер
  • 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: Блог Фироза Ансари

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

Это было полезно?

Решение

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

Действительно хороший сайт, на котором рассказывается об этом и других вещах: 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 от 15 сентября 2018 г., поэтому обе формы также работают в SQLite.

Другие советы

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

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

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

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

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

select *
from thetable
limit n-1, 1

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

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

А в SQL:2008 был добавлен немного более простой подход:
OFFSET пропускать ROWS FETCH FIRST н ROWS ONLY

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

Оракул:

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-СЕРВЕР


Выбрать 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

Здесь вы можете получить последнюю строку, заполнив N=0, вторую последнюю строку, заполнив N=1, четвертую последнюю строку, заполнив N=3 и так далее.

Это очень распространенный вопрос на собеседовании, и он очень прост.

Кроме того, если вам нужна сумма, идентификатор или какой-либо числовой порядок сортировки, вы можете использовать функцию CAST в MySQL.

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

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

ДОБАВЛЯТЬ:

LIMIT n,1

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

Например, если вы хотите выбрать каждую 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 на любую цифру, какую захотите.

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

Вот общая версия процедуры, которую я недавно написал для 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);

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

В Oracle 12c вы можете использовать OFFSET..FETCH..ROWS вариант с ORDER BY

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

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

В Sybase SQL Anywhere:

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

Не забывайте ORDER BY, иначе это бессмысленно.

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 Server общий способ поиска по номеру строки выглядит следующим образом:

SET ROWCOUNT @row --@row = the row number you wish to work on.

Например:

set rowcount 20   --sets row to 20th row

select meat, cheese from dbo.sandwich --select columns from table at 20th row

set rowcount 0   --sets rowcount back to all rows

Это вернет информацию 20-й строки.Обязательно укажите после этого число строк 0.

невероятно, что вы можете найти механизм 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

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

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

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;

Это действительно зависит от возможности использовать подзапрос в предложении ограничения (который в SQLite равен LIMIT <реки, которые нужно пропустить>, <реки, которые нужно взять>). Выбор количества записей в таблице должен быть особенно эффективным, поскольку он является частью базы данных. метаданные, но это зависит от реализации базы данных.Кроме того, я не знаю, действительно ли запрос построит набор результатов перед получением N-й записи, но я надеюсь, что в этом нет необходимости.Обратите внимание: я не указываю пункт «упорядочить по».Возможно, было бы лучше «упорядочить» что-то вроде первичного ключа, который будет иметь индекс — получение N-й записи из индекса может быть быстрее, если база данных не может получить N-ю запись из самой базы данных без построения набора результатов. .

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

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;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top