2013-08-26 55 views
5

我使用PostgreSQL 9.1,我想利用這個技巧,從我的表中刪除重複: https://stackoverflow.com/a/3822833/2239537PostgreSQL用於銷燬「關係不存在」

所以,我的查詢看起來像這樣:

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 

但它顯示我

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

然而這一說法正常工作:

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 

任何想法如何讓它工作? 謝謝!

回答

14

這是因爲PostgreSQL中的CTE的工作原理與SQL Server中的CTE不同。在SQL Server中,CTE就像一個可更新的視圖,所以你可以從它們中刪除或更新它們,在PostgreSQL中你不能。

你可以加入CTE和刪除,如:

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) 

在另一方面,你可以寫裏面CTE DDL語句PostgreSQL中(見documentation),這可能是非常方便的。例如,你可以從card刪除所有行,然後插入只有那些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

哇,謝謝快速回復和有用的答案!爲我工作,只需添加「刪除FROM卡」,但這當然只是錯字。 –

+0

@AlexKartishev是的,謝謝,更新 –

+0

第一個解決方案似乎刪除表中的所有行。我不明白cte的行爲:如果我做'從cte選擇count(1),其中rn> 1'我得到正確的數字,但是'select select count(1)from card where id in(select id from cte where rn> 1)'返回所有行 –

5

我知道,你是問如何使用WITH語句解決您的問題,並得到了很好的答案已經。但我建議在你關聯的同一個問題中尋找替代方案。

這個呢?

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

這是我見過的在PostgreSQL中檢測和清除重複記錄的最清晰方式。謝謝。 –

+0

那麼,爲什麼我會得到這麼多downvotes?不告訴我是不公平的。 –

+0

可能是因爲你的解決方案要求已經存在一個唯一的密鑰(id)可以用在哪裏...原始問題沒有其中之一 –

0

對於我來說,像這樣工作在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);