J'ai une table dans PostgreSQL , j'exécute une requête avec plusieurs conditions qui renvoie plusieurs lignes, ordonnées par l'une des colonnes. En général c'est:
SELECT <some columns>
FROM mytable
<maybe some joins here>
WHERE <various conditions>
ORDER BY date DESC
Maintenant, je suis seulement intéressé à obtenir la première et la dernière ligne de cette requête. Je pouvais les obtenir en dehors de la base de données, dans mon application (et c’est ce que je fais en réalité), mais je me demandais si, pour de meilleures performances, je ne devrais pas obtenir de la base de données uniquement ces 2 enregistrements qui m’intéressaient réellement.
Et si oui, comment modifier ma requête?
[Avertissement: cela ne pourrait pas être le moyen le plus efficace de le faire]:
(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)
Vous voudrez peut-être essayer ceci, cela pourrait être plus rapide que de faire deux requêtes
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
Premier enregistrement:
SELECT <some columns> FROM mytable
<maybe some joins here>
WHERE <various conditions>
ORDER BY date ASC
LIMIT 1
Dernier enregistrement:
SELECT <some columns> FROM mytable
<maybe some joins here>
WHERE <various conditions>
ORDER BY date DESC
LIMIT 1
dernier enregistrement:
SELECT * FROM `aboutus` order by id desc limit 1
premier enregistrement:
SELECT * FROM `aboutus` order by id asc limit 1
SELECT * FROM TABLE_NAME WHERE ROWID=(SELECT MIN(ROWID) FROM TABLE_NAME)
UNION
SELECT * FROM TABLE_NAME WHERE ROWID=(SELECT MAX(ROWID) FROM TABLE_NAME)
ou
SELECT * FROM TABLE_NAME WHERE ROWID=(SELECT MIN(ROWID) FROM TABLE_NAME)
OR ROWID=(SELECT MAX(ROWID) FROM TABLE_NAME)
Dans toutes les façons de faire exposées jusqu'à présent, il faut parcourir deux fois, une pour la première ligne et une pour la dernière.
En utilisant la fonction de fenêtre "ROW_NUMBER () OVER (...)" plus "WITH Queries", vous ne pouvez numériser qu'une fois et obtenir les deux éléments.
Fonction de la fenêtre: https://www.postgresql.org/docs/9.6/static/functions-window.html
WITH Queries: https://www.postgresql.org/docs/9.6/static/queries-with.html
Exemple:
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;
De cette façon, vous ne ferez qu’une fois les relations, filtrations et manipulations de données.
Essayez quelques explications ANALYSE des deux manières.
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}));
-- 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
);
Je l'ai eu ici: https://wiki.postgresql.org/wiki/First/last_(aggregate)
SELECT
MIN(Column), MAX(Column), UserId
FROM
Table_Name
WHERE
(Conditions)
GROUP BY
UserId DESC
ou
SELECT
MAX(Column)
FROM
TableName
WHERE
(Filter)
UNION ALL
SELECT
MIN(Column)
FROM
TableName AS Tablename1
WHERE
(Filter)
ORDER BY
Column