2013-08-26 4 views
5

Sto usando PostgreSQL 9.1 e voglio eliminare i duplicati dal mio tavolo con questo suggerimento: https://stackoverflow.com/a/3822833/2239537PostgreSQL con-delete "relazione non esiste"

Quindi, la mia domanda si presenta così:

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 

Ma mi

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

mostra Tuttavia questa dichiarazione funziona bene:

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 

Qualche idea su come farlo funzionare? Grazie!

risposta

14

questo perché CTE in PostgreSQL funziona in modo diverso rispetto a CTE in SQL Server. In SQL Server CTE sono come viste aggiornabili, quindi puoi eliminarle o aggiornarle, in PostgreSQL non è possibile.

si può aderire CTE ed eliminare, come:

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) 

D'altra parte, è possibile scrivere istruzioni DDL all'interno CTE in PostgreSQL (vedi documentation) e questo potrebbe essere molto utile. Ad esempio, è possibile eliminare tutte le righe da card e quindi inserire solo quelli con 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, grazie per la risposta rapida e risposta utile! Ha funzionato per me, ha solo dovuto aggiungere "delete FROM card", ma questo è solo un errore di battitura, ovviamente. –

+0

@AlexKartishev si, grazie, aggiornato –

+0

La prima soluzione sembra cancellare tutte le righe nella tabella per me. Non capisco il comportamento di cte: se seleziono 'select count (1) da cte dove rn> 1' ottengo il numero corretto, ma' select count (1) dalla scheda dove id in (selezionare id da cte dove rn> 1) 'restituisce tutte le righe –

5

Lo so, ti stai chiedendo come è possibile risolvere il problema utilizzando l'istruzione CON, ed ha ottenuto già una buona risposta . Ma suggerisco di guardare le alternative nella stessa domanda che hai collegato.

Che dire di questo?

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

Questo è il modo più chiaro che ho visto per rilevare e pulire i record duplicati in PostgreSQL. Grazie. –

+0

Allora perché ricevo così tanti downvotes? Non è giusto non dirmelo. –

+0

probabilmente perché la tua soluzione richiede che esista già una chiave univoca (id) che può essere utilizzata nel dove ... la domanda originale non ha uno di quelli –

0

Per me ha funzionato come questo 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);