Ich habe eine Tabelle in PostgreSQL und führe eine Abfrage mit mehreren Bedingungen aus, die mehrere Zeilen zurückgibt, die nach einer der Spalten sortiert sind. Im Allgemeinen ist es:
SELECT <some columns>
FROM mytable
<maybe some joins here>
WHERE <various conditions>
ORDER BY date DESC
Jetzt bin ich nur daran interessiert, die erste und die letzte Zeile aus dieser Abfrage zu erhalten. Ich konnte sie außerhalb der Datenbank, innerhalb meiner Anwendung (und das ist, was ich tatsächlich mache) bekommen, fragte mich aber, ob ich für eine bessere Leistung nicht nur die 2 Datensätze aus der Datenbank bekommen sollte, an denen ich tatsächlich interessiert bin.
Und wenn ja, wie ändere ich meine Abfrage?
sql
postgresql
Kender
quelle
quelle
SELECT DISTINCT ON (...) ... ORDER BY ...
. Siehe PostgreSQL-Dokumentation .Antworten:
[Vorsichtsmaßnahme: Könnte nicht der effizienteste Weg sein, dies zu tun]:
(SELECT <some columns> FROM mytable <maybe some joins here> WHERE <various conditions> ORDER BY date DESC LIMIT 1) UNION ALL (SELECT <some columns> FROM mytable <maybe some joins here> WHERE <various conditions> ORDER BY date ASC LIMIT 1)
quelle
(SELECT ... LIMIT 1) UNION ALL (SELECT ... LIMIT 1)
Vielleicht möchten Sie dies versuchen, möglicherweise schneller als zwei Abfragen:
select <some columns> from ( SELECT <some columns>, row_number() over (order by date desc) as rn, count(*) over () as total_count FROM mytable <maybe some joins here> WHERE <various conditions> ) t where rn = 1 or rn = total_count ORDER BY date DESC
quelle
Erste Aufzeichnung:
SELECT <some columns> FROM mytable <maybe some joins here> WHERE <various conditions> ORDER BY date ASC LIMIT 1
Letzte Aufzeichnung:
SELECT <some columns> FROM mytable <maybe some joins here> WHERE <various conditions> ORDER BY date DESC LIMIT 1
quelle
letzte Aufzeichnung:
SELECT * FROM `aboutus` order by id desc limit 1
erste Aufzeichnung:
SELECT * FROM `aboutus` order by id asc limit 1
quelle
"
zum Zitieren von Objektnamen - und sie werden hier sowieso überhaupt nicht benötigt)Bei allen bisher verfügbaren Vorgehensweisen muss der Scan zweimal durchgeführt werden, einer für die erste und einer für die letzte Zeile.
Mit der Fensterfunktion "ROW_NUMBER () OVER (...)" plus "WITH Queries" können Sie nur einmal scannen und beide Elemente abrufen.
Fensterfunktion: https://www.postgresql.org/docs/9.6/static/functions-window.html
MIT Abfragen: https://www.postgresql.org/docs/9.6/static/queries-with.html
Beispiel:
WITH scan_plan AS ( SELECT <some columns>, ROW_NUMBER() OVER (ORDER BY date DESC) AS first_row, /*It's logical required to be the same as major query*/ ROW_NUMBER() OVER (ORDER BY date ASC) AS last_row /*It's rigth, needs to be the inverse*/ FROM mytable <maybe some joins here> WHERE <various conditions> ORDER BY date DESC) SELECT <some columns> FROM scan_plan WHERE scan_plan.first_row = 1 OR scan_plan.last_row = 1;
Auf diese Weise führen Sie Beziehungen, Filterungen und Datenmanipulationen nur einmal durch.
Versuchen Sie es mit EXPLAIN ANALYZE auf beiden Wegen.
quelle
count(*) over () as total_count
Obige ist etwas leistungsfähiger, da nur eines verwendet wirdWindowAgg
und der Datensatz ebenfalls nur einmal sortiert wird.SELECT <rows> FROM TABLE_NAME WHERE ROWID=(SELECT MIN(ROWID) FROM TABLE_NAME) UNION SELECT <rows> FROM TABLE_NAME WHERE ROWID=(SELECT MAX(ROWID) FROM TABLE_NAME)
oder
SELECT * FROM TABLE_NAME WHERE ROWID=(SELECT MIN(ROWID) FROM TABLE_NAME) OR ROWID=(SELECT MAX(ROWID) FROM TABLE_NAME)
quelle
rowid
, es heißtctid
dort (und weder die Rowid von Oracle noch die Ctid von PostgreSQL garantieren eine Bestellung)SELECT * FROM TABLE_NAME WHERE rowid=(SELECT MIN(rowid) FROM TABLE_NAME) OR rowid=(SELECT MAX(rowid) FROM TABLE_NAME)
select * from {Table_Name} where {x_column_name}=( select d.{x_column_name} from ( select rownum as rno,{x_column_name} from {Table_Name})d where d.rno=( select count(*) from {Table_Name}));
quelle
-- Create a function that always returns the first non-NULL item CREATE OR REPLACE FUNCTION public.first_agg ( anyelement, anyelement ) RETURNS anyelement LANGUAGE SQL IMMUTABLE STRICT AS $$ SELECT $1; $$; -- And then wrap an aggregate around it CREATE AGGREGATE public.FIRST ( sfunc = public.first_agg, basetype = anyelement, stype = anyelement ); -- Create a function that always returns the last non-NULL item CREATE OR REPLACE FUNCTION public.last_agg ( anyelement, anyelement ) RETURNS anyelement LANGUAGE SQL IMMUTABLE STRICT AS $$ SELECT $2; $$; -- And then wrap an aggregate around it CREATE AGGREGATE public.LAST ( sfunc = public.last_agg, basetype = anyelement, stype = anyelement );
Habe es von hier bekommen: https://wiki.postgresql.org/wiki/First/last_(aggregate)
quelle
In einigen Fällen - wenn nicht so viele Spalten - nützlich sind die WINDOW-Funktionen FIRST_VALUE () und LAST_VALUE ().
SELECT FIRST_VALUE(timestamp) over (ORDER BY timestamp ASC) as created_dt, LAST_VALUE(timestamp) over (ORDER BY timestamp ASC) as last_update_dt, LAST_VALUE(action) over (ORDER BY timestamp ASC) as last_action FROM events
Diese Abfrage sortiert Daten nur einmal.
Es kann verwendet werden, um die ersten und letzten Zeilen anhand einer ID abzurufen
SELECT DISTINCT order_id, FIRST_VALUE(timestamp) over (PARTITION BY order_id ORDER BY timestamp ASC) as created_dt, LAST_VALUE(timestamp) over (PARTITION BY order_id ORDER BY timestamp ASC) as last_update_dt, LAST_VALUE(action) over (PARTITION BY order_id ORDER BY timestamp ASC) as last_action FROM events as x
quelle
SELECT MIN(Column), MAX(Column), UserId FROM Table_Name WHERE (Conditions) GROUP BY UserId DESC
oder
SELECT MAX(Column) FROM TableName WHERE (Filter) UNION ALL SELECT MIN(Column) FROM TableName AS Tablename1 WHERE (Filter) ORDER BY Column
quelle
So erhalten Sie den ersten und letzten Datensatz der Datenbank in c #.
SELECT TOP 1 * FROM ViewAttendenceReport WHERE EmployeeId = 4 AND AttendenceDate >='1/18/2020 00:00:00' AND AttendenceDate <='1/18/2020 23:59:59' ORDER BY Intime ASC UNION SELECT TOP 1 * FROM ViewAttendenceReport WHERE EmployeeId = 4 AND AttendenceDate >='1/18/2020 00:00:00' AND AttendenceDate <='1/18/2020 23:59:59' ORDER BY OutTime DESC;
quelle
Ich denke, dieser Code wird gleich und ist leichter zu lesen.
SELECT <some columns> FROM mytable <maybe some joins here> WHERE date >= (SELECT date from mytable) OR date <= (SELECT date from mytable);
quelle
Warum nicht verwenden
order by asc limit 1
und umgekehrtorder by desc limit 1
?quelle