96 votes

Comment récupérer le premier et le dernier enregistrement d'une requête sql ?

Dans PostgreSQL, j'exécute une requête avec plusieurs conditions qui renvoie plusieurs lignes, ordonnées par l'une des colonnes. Exemple :

SELECT <some columns> 
FROM mytable
<maybe some joins here>
WHERE <various conditions>
ORDER BY date DESC

Comment obtenir la première et la dernière ligne de cette requête ?

7voto

sundeepkumar dv Points 21
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)

o

SELECT * FROM TABLE_NAME WHERE ROWID=(SELECT MIN(ROWID) FROM TABLE_NAME) 
                            OR ROWID=(SELECT MAX(ROWID) FROM TABLE_NAME)

5voto

Wylie Solara Points 41

Je sais qu'il s'agit d'un fil de discussion vieux de 7 ans, mais la question était presque identique et la réponse acceptée était celle avec laquelle j'ai commencé et que j'ai finalement optimisée pour obtenir ce qui suit, qui dans mon cas donne des résultats cohérents. 85ms +-5ms avec <some_column> étant un champ int indexé.

note1 L'exemple UNION ALL dans la réponse acceptée fonctionne également mais était moins performant dans mon cas avec 300ms +-20ms.

note2 La réponse suivante la plus votée (l'exemple du compteur de lignes) fonctionne également mais était la moins performante dans mon cas, avec 800 ms + 70 ms.

select
  (select <some_column> from <some_table>
    order by <some_field> limit 1)        as oldest,
  (select <some_column> from <some_table> 
    order by <some_field> desc limit 1)   as newest
;

J'ai bien noté que l'op faisait référence à d'éventuelles jonctions. Je n'ai pas eu besoin d'inclure des jointures pour mes propres besoins (je me contente d'obtenir les identifiants les plus bas et les plus élevés dans une vue assez dynamique), mais avec ce modèle, les sous-requêtes pour l'identifiant le plus ancien et le plus récent devraient pouvoir être des requêtes à part entière. Je n'ai pas testé, donc je ne suis pas sûr que cela fonctionnerait ou serait optimal.

J'ai testé ce modèle (qui a peut-être déjà été suggéré ci-dessus) qui pourrait être un peu plus facile à comparer, mais la performance telle quelle était juste un peu moins de la moitié de l'exemple ci-dessus, avec un résultat constant de 220 ms +-10 ms dans mon cas.

select oldest.<some_field> as old, 
       newest.<some_field> as new  
from
  (select <some_column> from <some_table>
    order by <some_field> limit 1)        as oldest,
  (select <some_column> from <some_table> 
    order by <some_field> desc limit 1)   as newest
;

2voto

Dans certains cas, les fonctions WINDOW FIRST_VALUE() et LAST_VALUE() sont utiles. Le principal avantage de cette requête est qu'elle peut être réutilisée, que les données ne sont triées qu'une seule fois et qu'il n'est pas nécessaire de les trier. une seule requête pour plusieurs colonnes.

 SELECT
    FIRST_VALUE(timestamp) over w as created_dt,
    LAST_VALUE(timestamp) over w as last_update_dt,
    LAST_VALUE(action) over w as last_action
FROM events
WINDOW w as (ORDER BY timestamp ASC)

Il peut être utilisé pour obtenir la première et la dernière ligne en fonction d'un identifiant.

SELECT DISTINCT
    order_id,
    FIRST_VALUE(timestamp) over w as created_dt,
    LAST_VALUE(timestamp) over w as last_update_dt,
    LAST_VALUE(action) over w as last_action

FROM events as x
WINDOW w as (PARTITION BY order_id ORDER BY timestamp ASC)

1voto

Ampolu Balaji Points 11
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}));

1voto

-- 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 trouvé ici : https://wiki.postgresql.org/wiki/First/last_(agrégat)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X