it-swarm.com.de

Wie lösche ich eine feste Anzahl von Zeilen beim Sortieren in PostgreSQL?

Ich versuche, einige alte MySQL-Abfragen nach PostgreSQL zu portieren, aber ich habe Probleme mit diesem:

DELETE FROM logtable ORDER BY timestamp LIMIT 10;

PostgreSQL erlaubt keine Reihenfolge oder Begrenzungen in seiner Löschsyntax, und die Tabelle hat keinen Primärschlüssel, daher kann ich keine Unterabfrage verwenden. Darüber hinaus möchte ich das Verhalten beibehalten, bei dem die Abfrage genau die angegebene Anzahl oder Datensätze löscht. Wenn beispielsweise die Tabelle 30 Zeilen enthält, sie jedoch alle denselben Zeitstempel haben, möchte ich trotzdem 10 löschen, obwohl dies der Fall ist egal welche 10.

So; Wie lösche ich eine feste Anzahl von Zeilen beim Sortieren in PostgreSQL?

Bearbeiten: Kein Primärschlüssel bedeutet, dass es keine log_id-Spalte oder ähnliches gibt. Ah, die Freuden von Altsystemen!

77
Whatsit

Sie könnten versuchen, die ctid zu verwenden:

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

Die ctid lautet:

Der physische Ort der Zeilenversion in ihrer Tabelle. Obwohl ctid zum schnellen Auffinden der Zeilenversion verwendet werden kann, ändert sich ctid einer Zeile, wenn sie von VACUUM FULL aktualisiert oder verschoben wird. Daher ist ctid als langfristiger Zeilenbezeichner unbrauchbar.

Es gibt auch oid, das aber nur existiert, wenn Sie beim Erstellen der Tabelle ausdrücklich danach fragen.

117
mu is too short

Postgres-Dokumente empfehlen die Verwendung von array anstelle von IN und Unterabfrage. Das sollte viel schneller funktionieren 

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

Diese und einige andere Tricks finden Sie hier

39
criticus
delete from logtable where log_id in (
    select log_id from logtable order by timestamp limit 10);
11
Konrad Garus

Angenommen, Sie möchten ANY 10 Datensätze (ohne Bestellung) löschen, können Sie Folgendes tun:

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

Für meinen Anwendungsfall, 10M-Datensätze löschen, erwies sich dies als schneller.

2
Patrick Hüsler

Sie können eine Prozedur schreiben, die das Löschen für einzelne Zeilen durchläuft. Die Prozedur kann einen Parameter erfordern, um die Anzahl der Elemente anzugeben, die Sie löschen möchten. Im Vergleich zu MySQL ist das jedoch ein wenig übertrieben.

1
Bernhard

Wenn Sie keinen Primärschlüssel haben, können Sie die Where IN-Syntax des Arrays mit einem zusammengesetzten Schlüssel verwenden.

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

Das hat bei mir funktioniert.

0
user2449151