web-dev-qa-db-fra.com

Obtenir le dernier enregistrement d'une table dans Postgres

J'utilise Postgres et n'arrive pas à obtenir le dernier enregistrement de ma table:

 my_query = client.query("SELECT timestamp,value,card from my_table");

Comment puis-je savoir que l'horodatage est un identificateur unique de l'enregistrement?

27
Luc

Si sous "dernier enregistrement" vous voulez dire l'enregistrement qui a la dernière valeur d'horodatage, essayez ceci:

my_query = client.query("
  SELECT TIMESTAMP,
    value,
    card
  FROM my_table
  ORDER BY TIMESTAMP DESC
  LIMIT 1
");
62
bpgergo

vous pouvez utiliser

SELECT timestamp, value, card 
FROM my_table 
ORDER BY timestamp DESC 
LIMIT 1

en supposant que vous souhaitiez également trier par timestamp?

14
chl

Si vous acceptez un conseil, créez un identifiant dans cette table, tel que le nom de série. La valeur par défaut de ce champ sera:

nextval('table_name_field_seq'::regclass).

Donc, vous utilisez une requête pour appeler le dernier registre. En utilisant votre exemple:

pg_query($connection, "SELECT currval('table_name_field_seq') AS id;

J'espère que cette astuce vous aide.

6
phsaires

Le dernier enregistrement inséré peut être interrogé en utilisant ceci en supposant que vous avez l'id comme clé primaire:

SELECT timestamp,value,card FROM my_table WHERE id=(select max(id) from my_table)

En supposant que chaque nouvelle ligne insérée utilisera la valeur entière la plus élevée pour l'identifiant de la table.

4
Allan Registos

Manière simple: ORDER BY en conjonction avec LIMIT

SELECT timestamp, value, card
FROM my_table
ORDER BY timestamp DESC
LIMIT 1;

Cependant, LIMIT n'est pas standard et comme indiqué par Wikipedia , , la fonctionnalité principale du standard SQL ne définit pas explicitement un ordre de tri par défaut pour les valeurs Null. Enfin, une seule ligne est renvoyée lorsque plusieurs enregistrements partagent l’horodatage maximal.

Manière relationnelle:

Pour ce faire, il est généralement utile de vérifier qu'aucune ligne ne possède un horodatage plus élevé que toutes les lignes récupérées.

SELECT timestamp, value, card
FROM my_table t1
WHERE NOT EXISTS (
  SELECT *
  FROM my_table t2
  WHERE t2.timestamp > t1.timestamp
);

C'est ma solution préférée et celle que j'ai tendance à utiliser. L'inconvénient est que notre intention n'est pas immédiatement claire lorsque nous avons un aperçu de cette requête.

Manière instructive: MAX

Pour contourner ce problème, on peut utiliser MAX dans la sous-requête au lieu de la corrélation.

SELECT timestamp, value, card
FROM my_table
WHERE timestamp = (
  SELECT MAX(timestamp)
  FROM my_table
);

Mais sans index, deux passages sur les données seront nécessaires alors que la requête précédente peut trouver la solution avec un seul scan. Cela dit, nous ne devrions pas prendre en compte les performances lors de la conception des requêtes, sauf en cas de nécessité, car nous pouvons nous attendre à ce que les optimiseurs s'améliorent avec le temps. Cependant, ce type de requête est assez utilisé.

Manière d'exposition: Fonctions de fenêtrage

Je ne le recommande pas, mais vous pourrez peut-être faire bonne impression sur votre patron ou quelque chose du genre ;-)

SELECT DISTINCT
  first_value(timestamp) OVER w,
  first_value(value) OVER w,
  first_value(card) OVER w
FROM my_table
WINDOW w AS (ORDER BY timestamp DESC);

En fait, cela a le mérite de montrer qu’une simple requête peut être exprimée de différentes manières (il y en a plusieurs autres que je peux penser), et que choisir l’un ou l’autre formulaire devrait se faire selon plusieurs critères tels que:

  • portabilité (moyens relationnels/instructifs)
  • efficacité (manière relationnelle)
  • expressivité (manière simple/instructive)
2
Fabian Pijcke

Ce sont toutes de bonnes réponses, mais si vous souhaitez qu'une fonction d'agrégat agisse de cette manière, saisissez la dernière ligne du jeu de résultats généré par une requête arbitraire, il existe un moyen standard de le faire } _ (tiré du wiki Postgres, mais devrait fonctionner dans tout ce qui est raisonnablement conforme à la norme SQL à partir d’une décennie ou plus):

-- 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
);

Il est généralement préférable de faire select ... limit 1 si vous avez un ordre raisonnable, mais cela est utile si vous devez le faire dans un ensemble et préférez éviter une sous-requête.

Voir aussi cette question pour un cas où c'est la réponse naturelle.

0

Utilisez le suivant 

SELECT timestamp, value, card 
FROM my_table 
ORDER BY timestamp DESC 
LIMIT 1
0
LEMUEL ADANE

Si votre table n'a pas d'identifiant tel que l'incrémentation automatique d'entiers et pas d'horodatage, vous pouvez toujours obtenir la dernière ligne d'une table avec la requête suivante.

select * from <tablename> offset ((select count(*) from <tablename>)-1)

Par exemple, cela pourrait vous permettre de rechercher dans un fichier plat mis à jour, de rechercher/confirmer l'emplacement de la version précédente et de copier les lignes restantes dans votre tableau.

0
Hoser