Comment supprimer un nombre fixe de lignes avec Tri dans PostgreSQL?

J’essaie de porter quelques anciennes requêtes MySQL sur PostgreSQL, mais j’ai des problèmes avec celui-ci:

DELETE FROM logtable ORDER BY timestamp LIMIT 10; 

PostgreSQL n’autorise pas le classement ou les limites dans sa syntaxe de suppression, et la table ne possède pas de clé primaire. Je ne peux donc pas utiliser de sous-requête. De plus, je veux conserver le comportement où la requête supprime exactement le nombre ou les enregistrements donnés – par exemple, si la table contient 30 lignes mais qu’elles ont toutes le même horodatage, je souhaite quand même supprimer 10, bien que cela n’ait pas d’importance qui 10.

Alors; Comment supprimer un nombre fixe de lignes avec Tri dans PostgreSQL?

Edit: Aucune clé primaire signifie qu’il n’y a pas de colonne log_id ou similaire. Ah, les joies des systèmes hérités!

Vous pouvez essayer d’utiliser le ctid :

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

Le ctid est:

Emplacement physique de la version de ligne dans sa table. Notez que, bien que ctid puisse être utilisé pour localiser la version de ligne très rapidement, ctid une ligne changera si elle est mise à jour ou déplacée par VACUUM FULL . Par conséquent, ctid est inutile comme identifiant de ligne à long terme.

Il y a aussi oid mais cela n’existe que si vous le demandez spécifiquement lorsque vous créez la table.

Les documents postgres recommandent d’utiliser un tableau à la place de IN et 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

 delete from logtable where log_id in ( select log_id from logtable order by timestamp limit 10); 

En supposant que vous voulez supprimer TOUS 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, en supprimant 10M enregistrements, cela s'est avéré plus rapide.

Vous pouvez écrire une procédure qui effectue une boucle sur la suppression pour des lignes individuelles. La procédure peut prendre un paramètre pour spécifier le nombre d’éléments à supprimer. Mais c’est un peu exagéré par rapport à MySQL.

Si vous n’avez pas de clé primaire, vous pouvez utiliser la syntaxe du tableau Where IN avec une clé composite.

 delete from table1 where (schema,id,lac,cid) in (select schema,id,lac,cid from table1 where lac = 0 limit 1000); 

Cela a fonctionné pour moi.