166 votes

Comment puis-je supprimer un nombre fixe de lignes avec le tri dans PostgreSQL?

Je suis en train de le port certains vieux requêtes MySQL à PostgreSQL, mais je vais avoir des problèmes avec celui-ci:

DELETE FROM logtable ORDER BY timestamp LIMIT 10;

PostgreSQL ne permet pas de les commander ou de ses limites supprimer la syntaxe, et la table n'a pas une clé primaire donc je ne peux pas utiliser une sous-requête. En outre, je tiens à préserver le comportement où la requête supprime exactement le nombre donné ou des documents, par exemple, si la table contient 30 lignes, mais ils ont tous la même heure, j'ai encore envie de supprimer 10, bien qu'il n'a pas d'importance qui 10.

Alors, comment puis-je supprimer un nombre fixe de lignes avec le tri dans PostgreSQL?

Edit: Aucune clé primaire n'y a pas de log_id colonne ou similaire. Ah, les joies de l'héritage des systèmes!

243voto

mu is too short Points 205090

Vous pouvez essayer d'utiliser l' ctid:

DELETE FROM logtable
WHERE ctid IN (
    SELECT ctid
    FROM logtable
    ORDER BY timestamp
    LIMIT 10
)

L' ctid est:

L'emplacement physique de la version de ligne à l'intérieur de sa table. Notez que bien que l' ctid peut être utilisé pour localiser la version de ligne très rapidement, une ligne, ctid va changer, si elle est mise à jour ou déplacé en VACUUM FULL. Par conséquent, ctid est inutile à long terme, l'identificateur de ligne.

Il y a aussi oid mais qui n'existe que si vous demandez spécifiquement pour elle lorsque vous créez la table.

77voto

criticus Points 657

Les documents Postgres recommandent d'utiliser array au lieu de IN et de sous-requête. Cela devrait fonctionner beaucoup plus vite

 DELETE FROM logtable 
WHERE id = any (array(SELECT id FROM logtable ORDER BY timestamp LIMIT 10));
 

Ceci et quelques autres astuces peuvent être trouvés ici

21voto

Konrad Garus Points 19280
delete from logtable where log_id in (
    select log_id from logtable order by timestamp limit 10);

2voto

Patrick Hüsler Points 66

En supposant que vous vouliez supprimer 10 enregistrements (sans la commande), vous pouvez le faire:

 DELETE FROM logtable as t1 WHERE t1.ctid < (select t2.ctid from logtable as t2  where (Select count(*) from logtable t3  where t3.ctid < t2.ctid ) = 10 LIMIT 1);
 

Pour mon cas d'utilisation, la suppression de 10 millions d'enregistrements s'est avérée plus rapide.

0voto

Bernhard Points 2670

Vous pouvez écrire une procédure qui effectue une boucle sur la suppression pour des lignes individuelles, un processus permettant de spécifier le nombre d’éléments à supprimer. Mais c'est un peu exagéré par rapport à MySQL.

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