Wie wähle ich die n-te Zeile in einer SQL-Datenbanktabelle aus?
-
08-06-2019 - |
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?
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;