2009-10-06 12 views
13

ich dabei bin eine Django-DB-Replikation App verallgemeinert und verwendet die Anweisung:Wie universell ist die LIMIT-Anweisung in SQL?

SELECT %s FROM %s LIMIT 1 

1 Zeile zu holen und den Python DBAPI verwenden, um die Felder zu beschreiben, es funktioniert mit ORACLE und MySQL in Ordnung, aber , wie plattformübergreifend ist die LIMIT-Anweisung?

+0

Welche Version von Oracle funktioniert das in? –

+0

ORACLE 9i @ AlphaServer, mein Fehler, habe es gerade versucht, funktioniert nicht :( –

Antwort

2

Es funktioniert nicht auf MSSQL (die SELECT TOP 10 * FROM Blah stattdessen verwendet). Damit entfällt ein erheblicher Teil des DB-Marktes. Ich bin mir über andere nicht sicher.

Auch ist es möglich, obwohl sehr unwahrscheinlich, dass Ihre DB API es für Sie übersetzen wird.

2

LIMIT ist nicht Teil des ANSI SQL-Standard als den 1992-Standard; Ich habe keine Kopie eines späteren Standards zur Hand. Die Einhaltung des Standards durch die Anbieter ist in den besten Zeiten ziemlich vage. Wofür es sich lohnt, "LIMIT" wird als reserviertes Wort aufgeführt (dh es kann nicht legal als Bezeichner verwendet werden, auch wenn es sich bei der Implementierung nicht um ein Schlüsselwort handelt).

12

LIMIT ist sehr weit von universal - aus großen RDBMS, es ist ziemlich viel zu MySQL und PostgreSQL beschränkt. Here ist eine detaillierte Analyse, wie dies in vielen anderen Implementierungen durchgeführt wird, einschließlich MSSQL, Oracle und DB2 sowie in ANSI SQL.

6

Es ist überhaupt nicht universell. Eigentlich bin ich überrascht, dass es für dich in Oracle funktioniert; es war nicht anwesend. Normalerweise gehen Oracle-Benutzer für ROWNUM.

Jede Datenbank hat ihre eigene Syntax zur Begrenzung der Ergebnisse nach Zeilennummer. Darüber hinaus gibt es zwei Methoden, die ANSI SQL-Standard sind:

  1. FETCH FIRST. Abgeleitet von DB/2 und nur Standard in SQL: 2008, also sehr wenig DBMS-Unterstützung. Kann keinen Offset verwenden.

  2. Die Fensterfunktion SELECT ..., ROW_NUMBER() OVER (ORDER BY some_ordering) AS rn WHERE rn BETWEEN n AND m ... ORDER BY some_ordering. Dies ist von SQL: 2003 und hat einige (lückenhafte, manchmal langsame) Unterstützung in neueren DBMS. Es kann einen Offset oder irgendeine andere Vergleichsfunktion für die Zeilennummer verwenden, hat aber den Nachteil, entsetzlich hässlich zu sein.

Here's a good overview der Langweiligkeit müssen Sie beschäftigen, wenn Sie Cross-DBMS Paginierung Unterstützung möchten.

+0

+1 für einen wirklich guten Link auf plattformübergreifende Möglichkeiten, LIMIT auszudrücken. – ash108

20

LIMIT hat mit einer Vielzahl von Open-Source-Datenbanken ziemlich populär geworden, aber leider ist die Tatsache, dass OFFSET Paginierung über die am wenigsten standardisierte SQL-Funktion von ihnen war alles, so spät wie in SQL:2008 standardisiert wurde.

Bis dahin die jOOQ user manual page on the LIMIT clause zeigt, wie die verschiedenen äquivalenten Aussagen können in jedem SQL-Dialekt gebildet werden:

-- 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 

Nun, dies alles ziemlich geradlinig war, nicht wahr? Hier kommt der böse Teil, wenn man sie emulieren:

-- 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

Wählen Sie Ihr Gift ;-)

+0

In SQL Server erfordert die Verwendung von OFFSET und FETCH NEXT eine ORDER BY-Klausel – BoltBait

+0

@BoltBait: Du hast Recht, ich vergesse das. Danke! –

+0

Also überspringen diese Aussagen alle zwei Elemente und geben eins zurück, richtig? Mit der oberflächlichen Ausnahme der Aussagen mit dem Titel "ohne Offset". –

Verwandte Themen