Насколько универсальна инструкция LIMIT в SQL?
Я собираюсь обобщить приложение репликации Django DB, и он использует оператор:
SELECT %s FROM %s LIMIT 1
чтобы извлечь 1 строку и использовать PAP-интерфейс Python для описания полей, он отлично работает с ORACLE и MySQL, но как кросс-платформа является оператором LIMIT?
Ответы
Ответ 1
http://en.wikipedia.org/wiki/Select_(SQL)#Result_limits перечислены все основные варианты команды select.
Я считаю, что лучший способ сделать это - использовать команду SET ROWCOUNT перед оператором SELECT.
Итак, для вас:
SET ROWCOUNT 1
SELECT %s FROM %s
Ответ 2
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()
vs. DENSE_RANK()
здесь
Выберите свой яд; -)
Ответ 3
LIMIT
очень далек от универсального - из основных РСУБД, он в значительной степени ограничен MySQL и PostgreSQL. Здесь представлен подробный анализ того, как это делается во многих других реализациях, включая MSSQL, Oracle и DB2, а также в ANSI SQL.
Ответ 4
Это совсем не универсально. На самом деле я удивлен, что он работает для вас в Oracle; он не присутствовал. Обычно пользователи Oracle идут на ROWNUM
.
Каждая база данных имеет свой собственный синтаксис для ограничения результатов по номеру строки. Существуют также два метода, которые являются стандартными стандартами ANSI:
-
FETCH FIRST
. Производится из DB/2 и только стандартизован в SQL: 2008, поэтому очень мало поддержки СУБД. Невозможно использовать смещение.
-
Функция окна SELECT ..., ROW_NUMBER() OVER (ORDER BY some_ordering) AS rn WHERE rn BETWEEN n AND m ... ORDER BY some_ordering
. Это от SQL: 2003 и имеет некоторую (неоднородную, иногда медленную) поддержку в новых СУБД. Он может использовать смещение или любую другую функцию сравнения на номере строки, но имеет недостаток в ужасающем уродстве.
Вот хороший обзор о утомительности, с которой вам придется иметь дело, если вы хотите, чтобы поддержка разбивки на страницы с использованием нескольких СУБД.
Ответ 5
Он не работает в MSSQL (вместо этого используется SELECT TOP 10 * FROM Blah
). Это сокращает значительную часть рынка БД. Я не уверен в других.
Кроме того, возможно, хотя и очень маловероятно, что ваш DB API переведет его для вас.
Ответ 6
LIMIT не входит в стандарт ANSI SQL со стандартом 1992 года; У меня нет копии какого-либо более позднего стандарта. В лучшем случае соблюдение стандартов поставщиками довольно смутно. Для чего это стоит, "LIMIT" указан как зарезервированное слово (это означает, что его нельзя использовать в качестве идентификатора в качестве идентификатора даже в тех случаях, когда это не ключевое слово в реализации).