Frage

Ich bin daran interessiert, einige (idealerweise) datenbankunabhängige Möglichkeiten zur Auswahl kennenzulernen NZeile aus einer Datenbanktabelle.Es wäre auch interessant zu sehen, wie dies mithilfe der nativen Funktionalität der folgenden Datenbanken erreicht werden kann:

  • SQL Server
  • MySQL
  • PostgreSQL
  • SQLite
  • Orakel

Ich mache derzeit so etwas wie das Folgende in SQL Server 2005, aber ich wäre daran interessiert, die agnostischeren Ansätze anderer zu sehen:

WITH Ordered AS (
SELECT ROW_NUMBER() OVER (ORDER BY OrderID) AS RowNumber, OrderID, OrderDate
FROM Orders)
SELECT *
FROM Ordered
WHERE RowNumber = 1000000

Gutschrift für das obige SQL: Firoz Ansaris Weblog

Aktualisieren: Sehen Troels Arvins Antwort zum SQL-Standard. Troels, haben Sie Links, die wir zitieren können?

War es hilfreich?

Lösung

Es gibt Möglichkeiten, dies in optionalen Teilen des Standards zu tun, aber viele Datenbanken unterstützen ihre eigene Vorgehensweise.

Eine wirklich gute Seite, die über dieses und andere Dinge spricht, ist http://troels.arvin.dk/db/rdbms/#select-limit.

Grundsätzlich unterstützen PostgreSQL und MySQL das Nicht-Standard:

SELECT...
LIMIT y OFFSET x 

Oracle, DB2 und MSSQL unterstützen die Standard-Fensterfunktionen:

SELECT * FROM (
  SELECT
    ROW_NUMBER() OVER (ORDER BY key ASC) AS rownumber,
    columns
  FROM tablename
) AS foo
WHERE rownumber <= n

(was ich gerade von der oben verlinkten Seite kopiert habe, da ich diese Datenbanken nie verwende)

Aktualisieren: Ab PostgreSQL 8.4 werden die Standard-Fensterfunktionen unterstützt. Sie können also davon ausgehen, dass das zweite Beispiel auch für PostgreSQL funktioniert.

Aktualisieren: SQLite hat in Version 3.25.0 am 15.09.2018 die Unterstützung von Fensterfunktionen hinzugefügt, sodass beide Formulare auch in SQLite funktionieren.

Andere Tipps

Der LIMIT / OFFSET Syntax in PostgreSQL Ist:

SELECT
    *
FROM
    mytable
ORDER BY
    somefield
LIMIT 1 OFFSET 20;

In diesem Beispiel wird die 21. Zeile ausgewählt. OFFSET 20 weist Postgres an, die ersten 20 Datensätze zu überspringen.Wenn Sie keine angeben ORDER BY -Klausel gibt es keine Garantie, welchen Datensatz Sie zurückerhalten, was selten nützlich ist.

Anscheinend schweigt sich der SQL-Standard zum Limit-Problem außerhalb der verrückten Fensterfunktionen aus, weshalb jeder es anders implementiert.

Beim Rest bin ich mir nicht sicher, aber ich weiß, dass SQLite und MySQL keine „Standard“-Zeilenreihenfolge haben.Zumindest in diesen beiden Dialekten greift das folgende Snippet den 15. Eintrag aus the_table auf und sortiert ihn nach dem Datum/der Uhrzeit, zu der er hinzugefügt wurde:

SELECT * FROM the_table ORDER BY added DESC LIMIT 1,15

(Natürlich müssten Sie ein hinzugefügtes DATETIME-Feld haben und es auf das Datum/die Uhrzeit einstellen, an dem der Eintrag hinzugefügt wurde ...)

In SQL 2005 und höher ist diese Funktion integriert.Verwenden Sie die Funktion ROW_NUMBER().Es eignet sich hervorragend für Webseiten mit einem << Vorherigen und Nächsten >>-Browsing-Stil:

Syntax:

SELECT
    *
FROM
    (
        SELECT
            ROW_NUMBER () OVER (ORDER BY MyColumnToOrderBy) AS RowNum,
            *
        FROM
            Table_1
    ) sub
WHERE
    RowNum = 23

Ich vermute, dass dies völlig ineffizient ist, aber es handelt sich um einen recht einfachen Ansatz, der bei einem kleinen Datensatz, an dem ich ihn ausprobiert habe, funktioniert hat.

select top 1 field
from table
where field in (select top 5 field from table order by field asc)
order by field desc

Dies würde das 5. Element erhalten, die zweitoberste Zahl ändern, um ein anderes n-tes Element zu erhalten

Nur SQL Server (glaube ich), sollte aber auf älteren Versionen funktionieren, die ROW_NUMBER() nicht unterstützen.

Überprüfen Sie es auf SQL Server:

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

Dadurch erhalten Sie die 10. REIHE der Emp-Tabelle!

1 kleine Änderung:n-1 statt n.

select *
from thetable
limit n-1, 1

Im Gegensatz zu den Behauptungen einiger Antworten schweigt der SQL-Standard zu diesem Thema nicht.

Seit SQL:2003 können Sie „Fensterfunktionen“ verwenden, um Zeilen zu überspringen und Ergebnismengen einzuschränken.

Und in SQL:2008 wurde mit der Verwendung ein etwas einfacherer Ansatz hinzugefügt
OFFSET überspringen ROWS FETCH FIRST N ROWS ONLY

Persönlich glaube ich nicht, dass die Ergänzung von SQL:2008 wirklich nötig war. Wenn ich also ISO wäre, hätte ich sie aus einem ohnehin schon recht großen Standard herausgehalten.

Orakel:

select * from (select foo from bar order by foo) where ROWNUM = x

Als wir früher mit MSSQL 2000 arbeiteten, machten wir das, was wir „Triple-Flip“ nannten:

BEARBEITET

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

Es war weder elegant noch schnell, aber es funktionierte.

SQL SERVER


Wählen Sie den n-ten Datensatz von oben aus

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n

Wählen Sie den n-ten Datensatz von unten aus

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID DESC) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n

Hier finden Sie eine schnelle Lösung für Ihre Verwirrung.

SELECT * FROM table ORDER BY `id` DESC LIMIT N, 1

Hier können Sie die letzte Zeile durch Ausfüllen von N=0, die vorletzte Zeile durch Ausfüllen von N=1, die viertletzte Zeile durch Ausfüllen von N=3 usw. erhalten.

Dies ist eine sehr häufige Frage im Vorstellungsgespräch und die Antwort darauf ist sehr einfach.

Wenn Sie außerdem Betrag, ID oder eine numerische Sortierreihenfolge wünschen, können Sie sich für die CAST-Funktion in MySQL entscheiden.

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

Hier können Sie durch Ausfüllen von N = 4 den fünftletzten Datensatz mit dem höchsten Betrag aus der CART-Tabelle erhalten.Sie können Ihren Feld- und Tabellennamen anpassen und eine Lösung finden.

HINZUFÜGEN:

LIMIT n,1

Dadurch werden die Ergebnisse auf ein Ergebnis beschränkt, beginnend mit Ergebnis n.

Wenn Sie beispielsweise jede 10. Zeile in MSSQL auswählen möchten, können Sie Folgendes verwenden:

SELECT * FROM (
  SELECT
    ROW_NUMBER() OVER (ORDER BY ColumnName1 ASC) AS rownumber, ColumnName1, ColumnName2
  FROM TableName
) AS foo
WHERE rownumber % 10 = 0

Nehmen Sie einfach das MOD und ändern Sie hier die Nummer 10 in eine beliebige Nummer.

LIMIT n,1 funktioniert nicht in MS SQL Server.Ich denke, es ist so ziemlich die einzige große Datenbank, die diese Syntax nicht unterstützt.Fairerweise muss man sagen, dass es nicht Teil des SQL-Standards ist, obwohl es so weithin unterstützt wird, dass es sein sollte.In allem außer SQL Server funktioniert LIMIT großartig.Für SQL Server konnte ich keine elegante Lösung finden.

Hier ist eine generische Version eines Sproc, den ich kürzlich für Oracle geschrieben habe und der dynamisches Paging/Sortieren ermöglicht – 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);

Aber ist das alles nicht eigentlich nur ein Trick für ein gutes Datenbankdesign?Die wenigen Male, in denen ich eine solche Funktionalität benötigte, war es für eine einfache einmalige Abfrage, um einen schnellen Bericht zu erstellen.Bei jeder echten Arbeit ist die Verwendung solcher Tricks ein Ärgernis.Wenn Sie eine bestimmte Zeile auswählen müssen, erstellen Sie einfach eine Spalte mit einem sequentiellen Wert und fertig.

In Oracle 12c können Sie verwenden OFFSET..FETCH..ROWS Option mit ORDER BY

Um beispielsweise den dritten Datensatz von oben zu erhalten:

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

In Sybase SQL Anywhere:

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

Vergessen Sie nicht ORDER BY, sonst ist es bedeutungslos.

T-SQL – Auswahl der N-ten Datensatznummer aus einer Tabelle

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

Für z.B.Um den 5. Datensatz aus einer Tabelle „Mitarbeiter“ auszuwählen, sollte Ihre Abfrage lauten

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

Ich habe diese Abfrage geschrieben, um die N-te Zeile zu finden.Beispiel mit dieser Abfrage wäre

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

Für SQL Server ist eine generische Vorgehensweise für die Zeilennummer wie folgt:

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

Zum Beispiel:

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

Dadurch werden die Informationen der 20. Zeile zurückgegeben.Stellen Sie sicher, dass Sie anschließend die Zeilenanzahl 0 eingeben.

Unglaublich, dass es eine SQL-Engine gibt, die dies ausführt ...

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

Nichts Besonderes, keine besonderen Funktionen, falls Sie Caché wie ich verwenden ...

SELECT TOP 1 * FROM (
  SELECT TOP n * FROM <table>
  ORDER BY ID Desc
)
ORDER BY ID ASC

Vorausgesetzt, Sie verfügen über eine ID-Spalte oder eine Datumsstempelspalte, der Sie vertrauen können.

So würde ich es in DB2 SQL machen. Ich glaube, die RRN (relative Datensatznummer) wird vom Betriebssystem in der Tabelle gespeichert.

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;

Wählen Sie zuerst die obersten 100 Zeilen in aufsteigender Reihenfolge aus und wählen Sie dann die letzte Zeile in absteigender Reihenfolge aus und beschränken Sie die Reihenfolge auf 1.Dies ist jedoch eine sehr kostspielige Anweisung, da doppelt auf die Daten zugegriffen wird.

Mir scheint, dass man, um effizient zu sein, 1) eine Zufallszahl zwischen 0 und eins kleiner als die Anzahl der Datenbankeinträge generieren muss und 2) in der Lage sein muss, die Zeile an dieser Position auszuwählen.Leider verfügen verschiedene Datenbanken über unterschiedliche Zufallszahlengeneratoren und unterschiedliche Möglichkeiten, eine Zeile an einer Position in einer Ergebnismenge auszuwählen. Normalerweise geben Sie an, wie viele Zeilen übersprungen werden sollen und wie viele Zeilen Sie möchten, aber dies geschieht bei verschiedenen Datenbanken unterschiedlich.Folgendes funktioniert für mich in SQLite:

select * 
from Table 
limit abs(random()) % (select count(*) from Words), 1;

Es hängt davon ab, dass eine Unterabfrage in der Limit-Klausel verwendet werden kann (die in SQLite LIMIT <recs to ski>,<recs to take> ist). Die Auswahl der Anzahl der Datensätze in einer Tabelle sollte besonders effizient sein, da sie Teil der Datenbank ist Metadaten, aber das hängt von der Implementierung der Datenbank ab.Außerdem weiß ich nicht, ob die Abfrage tatsächlich die Ergebnismenge erstellt, bevor sie den N-ten Datensatz abruft, aber ich hoffe, dass dies nicht erforderlich ist.Beachten Sie, dass ich keine „order by“-Klausel spezifiziere.Es könnte besser sein, nach so etwas wie dem Primärschlüssel zu „sortieren“, der einen Index hat – das Abrufen des N-ten Datensatzes aus einem Index könnte schneller sein, wenn die Datenbank den N-ten Datensatz nicht aus der Datenbank selbst abrufen kann, ohne die Ergebnismenge zu erstellen .

Für SQL Server gibt Folgendes die erste Zeile aus der angegebenen Tabelle zurück.

declare @rowNumber int = 1;
    select TOP(@rowNumber) * from [dbo].[someTable];
EXCEPT
    select TOP(@rowNumber - 1) * from [dbo].[someTable];

Sie können die Werte folgendermaßen durchlaufen:

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;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top