Насколько универсален оператор LIMIT в SQL?

Я нахожусь в процессе обобщения приложения репликации Django DB, и оно использует оператор:

SELECT %s FROM %s LIMIT 1

чтобы получить 1 строку и использовать Python DBAPI для описания полей, он отлично работает с ORACLE и MySQL, но насколько кроссплатформенным является оператор LIMIT?


person Roberto Rosario    schedule 06.10.2009    source источник
comment
В какой версии Oracle это работает?   -  person WW.    schedule 07.10.2009
comment
ORACLE 9i @ AlphaServer, ошибка моя, попробовал, не работает :(   -  person Roberto Rosario    schedule 07.10.2009


Ответы (7)


http://en.wikipedia.org/wiki/Select_(SQL)#Limiting_result_rows перечисляет все основные варианты команды select.

Я считаю, что лучший способ сделать это - использовать команду SET ROWCOUNT перед оператором SELECT.

Итак, для вас:

SET ROWCOUNT 1
SELECT %s FROM %s
person BoltBait    schedule 06.10.2009

LIMIT стал довольно популярным в различных базах данных с открытым исходным кодом, но, к сожалению, факт заключается в том, что OFFSET разбиение на страницы было наименее стандартизированной функцией SQL из всех, поскольку она была стандартизирована только в SQL: 2008.

А пока пользователь jOOQ справочная страница в разделе LIMIT показывает, как различные эквивалентные операторы могут быть сформированы на каждом диалекте SQL:

-- MySQL, H2, HSQLDB, Postgres, and SQLite
SELECT * FROM BOOK LIMIT 1 OFFSET 2

-- CUBRID supports a MySQL variant of the LIMIT .. OFFSET clause
SELECT * FROM BOOK LIMIT 2, 1

-- Derby, SQL Server 2012, Oracle 12c, SQL:2008 standard
-- Some need a mandatory ORDER BY clause prior to OFFSET
SELECT * FROM BOOK [ ORDER BY ... ] OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY

-- Ingres
SELECT * FROM BOOK OFFSET 2 FETCH FIRST 1 ROWS ONLY

-- Firebird
SELECT * FROM BOOK ROWS 2 TO 3

-- Sybase SQL Anywhere
SELECT TOP 1 ROWS START AT 3 * FROM BOOK

-- DB2 (without OFFSET)
SELECT * FROM BOOK FETCH FIRST 1 ROWS ONLY

-- Sybase ASE, SQL Server 2008 (without OFFSET)
SELECT TOP 1 * FROM BOOK

Все это было довольно просто, не так ли? А вот и неприятная часть, когда вам нужно подражать им:

-- DB2 (with OFFSET), SQL Server 2008 (with OFFSET), 
SELECT * FROM (
  SELECT BOOK.*, 
    ROW_NUMBER() OVER (ORDER BY ID ASC) AS RN
  FROM BOOK
) AS X
WHERE RN > 2
AND RN <= 3

-- DB2 (with OFFSET), SQL Server 2008 (with OFFSET)
-- When the original query uses DISTINCT!
SELECT * FROM (
  SELECT DISTINCT BOOK.ID, BOOK.TITLE 
    DENSE_RANK() OVER (ORDER BY ID ASC, TITLE ASC) AS RN
  FROM BOOK
) AS X
WHERE RN > 2
AND RN <= 3

-- Oracle 11g and less
SELECT * 
FROM (
  SELECT b.*, ROWNUM RN 
  FROM (
    SELECT *
    FROM BOOK
    ORDER BY ID ASC
  ) b
  WHERE ROWNUM <= 3
) 
WHERE RN > 2

Обоснование ROW_NUMBER() и DENSE_RANK() читайте здесь

Выбери свой яд ;-)

person Lukas Eder    schedule 04.06.2014
comment
В SQL Server использование OFFSET и FETCH NEXT требует использования предложения ORDER BY. - person BoltBait; 24.09.2014
comment
@BoltBait: Ты прав, я все время забываю об этом. Спасибо! - person Lukas Eder; 24.09.2014
comment
Итак, все эти операторы пропускают два элемента и возвращают один, верно? За явным исключением заявлений, озаглавленных без зачета. - person Jens Schauder; 16.03.2017
comment
Я посмотрел на это снова, и мне кажется, что нижний блок пропускает 1 и возвращает два. Если это не так, мне хотелось бы получить объяснение. Например, последний пример должен возвращать три элемента в среднем выборе, а затем возвращать два последних из них во внешнем выборе, верно? - person Jens Schauder; 17.03.2017
comment
@JensSchauder: Ты прав, зоркий глаз. Исправлю сразу. - person Lukas Eder; 17.03.2017
comment
По поводу комментария от @BoltBait: понятие номера строки довольно неполное, если мы все не согласны с порядком строк. По этой причине я всегда рекомендую использовать ORDER BY, даже если это технически не требуется. В противном случае вы действительно запрашиваете любые строки. - person Manngo; 08.12.2017

LIMIT очень далек от универсального - из основных СУБД он в значительной степени ограничен MySQL и PostgreSQL. Здесь представлен подробный анализ того, как это делается во многих других реализациях, включая MSSQL, Oracle и DB2, а также в ANSI SQL.

person Pavel Minaev    schedule 06.10.2009

Это совсем не универсально. На самом деле я удивлен, что это работает для вас в Oracle; раньше его не было. Обычно пользователи Oracle выбирают ROWNUM.

Каждая база данных имеет собственный синтаксис для ограничения результатов по номеру строки. Есть также два метода, которые являются стандартным SQL ANSI:

  1. FETCH FIRST. Производный от DB / 2 и стандартизированный только в SQL: 2008, поэтому СУБД очень мало поддерживает. Невозможно использовать смещение.

  2. Оконная функция SELECT ..., ROW_NUMBER() OVER (ORDER BY some_ordering) AS rn WHERE rn BETWEEN n AND m ... ORDER BY some_ordering. Это из SQL: 2003 и имеет некоторую (неоднородную, иногда медленную) поддержку в новых СУБД. Он может использовать смещение или любую другую функцию сравнения для номера строки, но имеет недостаток в том, что он ужасно уродлив.

Вот хороший обзор того утомления, с которым вам придется столкнуться, если вы хотите поддержка разбивки на страницы между СУБД.

person bobince    schedule 06.10.2009
comment
+1 за действительно хорошую ссылку на кроссплатформенные способы выражения LIMIT. - person ash108; 18.02.2013

LIMIT не является частью стандарта ANSI SQL со стандарта 1992 года; У меня нет под рукой экземпляров более поздних стандартов. Соблюдение поставщиками стандарта в лучшие времена довольно расплывчато. Как бы то ни было, «LIMIT» указано как зарезервированное слово (что означает, что оно не может юридически использоваться в качестве идентификатора даже в тех случаях, когда оно не является ключевым словом в реализации).

person Tim Martin    schedule 06.10.2009

Он не работает на MSSQL (который вместо этого использует SELECT TOP 10 * FROM Blah). Это вырезает значительную часть рынка БД. Насчет других я не уверен.

Кроме того, возможно, хотя и очень маловероятно, что ваш API БД переведет его за вас.

person rmeador    schedule 06.10.2009

Поскольку в одном из ответов было упомянуто, что LIMIT и OFFSET более или менее ограничены MySQL и PostgreSQL, я подумал указать, что SAP HANA также поддерживает предложения LIMIT и OFFSET. Но OFFSET без LIMIT не разрешен в базе данных SAP HANA.

person Susa    schedule 04.05.2018