2013-08-26 19 views
5

Ich verwende postgreSQL 9.1 und ich möchte Duplikate aus meiner Tabelle löschen, diesen Tipp mit: https://stackoverflow.com/a/3822833/2239537PostgreSQL mit-löschen „Beziehung existiert nicht“

Also, meine Abfrage sieht wie folgt aus:

WITH cte 
AS (SELECT ROW_NUMBER() 
OVER (PARTITION BY code, card_id, parent_id 
    ORDER BY id DESC) RN 
    FROM card) 
DELETE FROM cte 
WHERE RN > 1 

Aber es zeigt mir

ERROR: relation "cte" does not exist 
SQL state: 42P01 
Character: 157 

Allerdings funktioniert diese Aussage fein:

WITH cte 
AS (SELECT ROW_NUMBER() 
OVER (PARTITION BY code, card_id, parent_id 
    ORDER BY id DESC) RN 
    FROM merchantcard) 
SELECT * FROM cte 
WHERE RN > 1 

Irgendwelche Ideen, wie es funktioniert? Danke!

Antwort

14

das ist, weil CTE in PostgreSQL anders als CTE in SQL Server funktioniert. In SQL Server CTE sind wie eine aktualisierbare Ansichten, so dass Sie sie löschen oder aktualisieren können, in PostgreSQL können Sie nicht.

Sie cte und löschen, wie beitreten können:

with cte as (
    select 
     id, 
     row_number() over(partition by code, card_id, parent_id order by id desc) as rn 
    from card 
) 
delete 
from card 
where id in (select id from cte where rn > 1) 

Auf der anderen Seite können Sie DDL-Anweisungen innerhalb von CTE in PostgreSQL (siehe documentation) schreiben und dies sehr nützlich sein könnte. Zum Beispiel können Sie alle Zeilen aus card löschen und fügen Sie dann nur solche mit row_number = 1:

with cte1 as (
    delete 
    from card 
    returning * 
), cte2 as (
    select 
     row_number() over(partition by code, card_id, parent_id order by id desc) as rn, 
     * 
    from cte1 
) 
insert into card 
select <columns here> 
from cte2 
where rn = 1 
+0

Wow, vielen Dank für die schnelle Antwort und nützliche Antwort! Arbeitete für mich, musste nur "löschen von der Karte" hinzufügen, aber das ist nur ein Tippfehler, natürlich. –

+0

@AlexKartischev ja, danke, aktualisiert –

+0

Die erste Lösung scheint alle Zeilen in der Tabelle für mich zu löschen. Ich verstehe das Verhalten von cte nicht: Wenn ich 'count (1) von cte where rn> 1 'wähle, bekomme ich die richtige Zahl, aber' zähle count (1) von der Karte wo ID in (wähle id aus cte wo rn> 1) 'gibt alle Zeilen zurück –

5

Ich weiß, Sie fragen, wie Sie Ihr Problem mit der WITH-Anweisung lösen kann, und bekam bereits eine gute Antwort . Aber ich schlage vor, Alternativen in derselben Frage zu suchen, die Sie verlinkt haben.

Was ist mit diesem?

DELETE FROM card 
WHERE id NOT IN (
    SELECT MIN(id) FROM card 
    GROUP BY code, card_id, parent_id 
); 
+1

Dies ist die klarste Art, wie ich doppelte Datensätze in PostgreSQL erkannt und bereinigt habe. Vielen Dank. –

+0

Warum bekomme ich so viele Downvotes? Es ist nicht fair, mir das nicht zu sagen. –

+0

wahrscheinlich, weil Ihre Lösung erfordert, dass es bereits einen eindeutigen Schlüssel (ID) gibt, der in dem verwendet werden kann, wo ... die ursprüngliche Frage keinen von denen hat –

0

Für mich ist es wie dies in Postgres/GreenPlum:

delete 
from card where id in (
with cte as (
    select 
     id, 
     row_number() over(partition by code, card_id, parent_id order by id desc) as rn 
    from card 
) 
select id from cte where rn > 1); 
Verwandte Themen