2017-10-01 4 views
0

Ich möchte die letzte Einfügung bis zu "n" Zeilen löschen.Postgres: Zeilenreihenfolge ohne Primärschlüssel löschen

Zum Beispiel:

DELETE FROM users 
WHERE user_id = %s AND group_id = %s 
ORDER BY message_date DESC 

ich, es ist ein Syntaxfehler verstanden und die Suche im Web mir viele Stackoverflow Antworten sagen, verwenden, um eine Form wie

DELETE FROM users 
WHERE id IN (SELECT id ....) 

Leider habe ich keine gefunden Primärschlüssel für diese Tabelle sind nur Inserts ohne automatisches Inkrement.

Wie kann ich es tun?

Vielleicht sollte ich so etwas wie

WITH t AS 
(
    SELECT * 
    FROM users 
    WHERE user_id = %s AND group_id = %s 
    ORDER BY message_date DESC 
) 
DELETE FROM t 

???

Antwort

1

können Sie den Code anpassen Sie IDs gefunden werden:

DELETE users u 
    WHERE u.user_id = %s AND u.group_id = %s AND 
      u.message_date IN (SELECT u2.message_date 
          FROM users u2 
          WHERE u2.user_id = u.user_id AND 
            u2.group_id = u.group_id 
          ORDER BY u2.message_date DESC 
          LIMIT <n> 
          ); 

Ich hoffe, haben daraus gelernt, wie nützlich serielle Primärschlüssel in einer Datenbank sein kann.

Hinweis: Dies kann mehr als Zeilen löschen, wenn Verbindungen in der Datenbank vorhanden sind.

EDIT:

Lassen Sie mich hinzufügen, würde ich eher geneigt, dies als zu nähern:

DELETE users u 
    FROM (SELECT u2.*, 
       ROW_NUMBER() OVER (PARTITION BY user_id, group_id ORDER BY message_date DESC) as seqnum 
      FROM users u2 
     ) u2 
     ON u2.user_id = u.user_id AND u2.group_id = u.group_id AND 
      u2.message_date = u.message_date 
    WHERE u.user_id = %s AND u.group_id = %s AND 
      seqnum <= <n>; 

Dies stellt sicher, dass genau Zeilen gelöscht werden, auch mit Verbindungen.

+0

Ja. In der Tat habe ich diese Frage gestellt, um den seriellen Primärschlüssel hinzuzufügen – 91DarioDev

1

Wenn kein Kandidat Schlüssel zu bestellen, indem Sie ist, können Sie immer ctid verwenden: (garantiert eindeutig sein)


DELETE FROM one 
WHERE EXISTS (
     SELECT * 
     FROM one x 
     WHERE x.oneseq <= 3 -- whatever condition 
     AND x.ctid = one.ctid 
     ORDER BY x.ctid 
     LIMIT 3 -- number of rows you want todelete 
     ); 

Dies funktioniert mit row_number() OVER (PARTITION BY...ORDER BY ctid) as rn auch. (Was natürlich unsinnig, da die ctid um mehr oder weniger zufällig sein wird sowieso)

1

Wenn Ihre Tabelle hat keine serielle IDs (zum Beispiel, wenn ein bestehender mehrspaltigen Primärschlüssel ist) Sie kann immer noch IN verwenden, um die Zeilen, die Sie löschen möchten, filtern:

DELETE FROM table_name 
WHERE (key1, key2) IN (
    SELECT key1, key2 FROM table_name ORDER BY date DESC LIMIT 2 
); 

Für Ihren speziellen Fall können Sie:

DELETE FROM users 
WHERE (user_id, group_id) IN (
    SELECT user_id, group_id FROM users 
    WHERE user_id = %s AND group_id = %s 
    ORDER BY message_date DESC 
); 
Verwandte Themen