2013-08-26 39 views
5

Tôi đang sử dụng PostgreSQL 9.1 và tôi muốn xóa các bản sao từ bàn của tôi sử dụng mẹo này: https://stackoverflow.com/a/3822833/2239537PostgreSQL với-delete "mối quan hệ không tồn tại"

Vì vậy, câu hỏi của tôi trông như thế:

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 

Nhưng nó cho thấy tôi

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

Tuy nhiên tuyên bố này hoạt động tốt:

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 

Bất kỳ ý tưởng nào làm cho nó hoạt động? Cảm ơn!

Trả lời

14

đó là vì CTE trong PostgreSQL hoạt động khác với CTE trong SQL Server. Trong SQL Server CTE giống như một khung nhìn có thể cập nhật, vì vậy bạn có thể xóa chúng hoặc cập nhật chúng, trong PostgreSQL bạn không thể.

bạn có thể tham gia chương trình CTE và xóa, như:

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) 

Mặt khác, bạn có thể viết DDL báo cáo bên trong CTE trong PostgreSQL (xem documentation) và điều này có thể là rất tiện dụng. Ví dụ, bạn có thể xóa tất cả các hàng từ card và sau đó chèn chỉ những người có 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, nhờ trả lời nhanh chóng và câu trả lời hữu ích! Làm việc cho tôi, chỉ phải thêm "xóa thẻ TỪ", nhưng tất nhiên đây chỉ là lỗi đánh máy. –

+0

@AlexKartishev vâng, cảm ơn, cập nhật –

+0

Giải pháp đầu tiên xuất hiện để xóa tất cả các hàng trong bảng cho tôi. Tôi không hiểu hành vi cte: nếu tôi thực hiện 'select count (1) từ cte nơi rn> 1' tôi nhận được số đúng, nhưng' select count (1) từ thẻ có id trong (select id from cte where rn> 1) 'trả về tất cả các hàng –

5

tôi biết, bạn đang yêu cầu làm thế nào bạn có thể giải quyết vấn đề của bạn sử dụng câu lệnh VỚI, và nhận được một câu trả lời tốt đã . Nhưng tôi đề nghị xem xét các lựa chọn thay thế trong cùng một câu hỏi mà bạn đã liên kết.

Còn cái này thì sao?

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

Đây là cách rõ ràng nhất mà tôi đã nhìn thấy để phát hiện và làm sạch các bản ghi trùng lặp trong PostgreSQL. Cảm ơn bạn. –

+0

Vậy tại sao tôi lại nhận được rất nhiều downvotes? Không công bằng khi nói với tôi. –

+0

có lẽ vì giải pháp của bạn yêu cầu phải có một khóa duy nhất (id) có thể được sử dụng ở nơi ... câu hỏi ban đầu không có một trong số đó –

0

Đối với tôi nó làm việc như thế này trong 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); 
Các vấn đề liên quan