2009-10-06 2 views
13

Я нахожусь в процессе обобщающего приложение репликации Django DB и использует оператор:Насколько универсальна инструкция LIMIT в SQL?

SELECT %s FROM %s LIMIT 1 

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

+0

Какую версию Oracle делает эту работу? –

+0

ORACLE 9i @ AlphaServer, моя ошибка, просто попробовал, не работает :( –

ответ

10

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

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

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

SET ROWCOUNT 1 
SELECT %s FROM %s 
2

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

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

2

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

12

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

6

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

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

  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 и имеет некоторую (неоднородную, иногда медленную) поддержку в новых СУБД. Он может использовать смещение или любую другую функцию сравнения для номера строки, но имеет недостаток в ужасающем уродстве.

Here's a good overview из занудства вам придется иметь дело с тем, если вы хотите поддержку постраничной кросс-СУБД.

+0

+1 для действительно хорошей ссылки на кросс-платформенные способы выражения LIMIT. – ash108

20

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

До тех пор, пока jOOQ user manual page on the LIMIT clause показывает, как различные эквивалентные высказывания могут быть сформированы в каждом 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 

Read about the ROW_NUMBER() vs. DENSE_RANK() rationale here

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

+0

В SQL Server с использованием OFFSET и FETCH NEXT требуется использование предложение ORDER BY. – BoltBait

+0

@BoltBait: Вы правы, я забыл об этом. Спасибо! –

+0

Итак, эти утверждения пропускают два элемента и возвращают один, верно? С заведомым исключением из выражений «без смещения». –