PostgreSQL with-delete "не существует"

Я использую postgreSQL 9.1, и я хочу удалить дубликаты из своей таблицы, используя этот совет: qaru.site/info/10777/...

Итак, мой запрос выглядит так:

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

Любые идеи, как заставить его работать? Спасибо!

Ответ 1

потому что CTE в PostgreSQL работает иначе, чем CTE в SQL Server. В 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)

С другой стороны, вы можете писать заявления DDL внутри CTE в PostgreSQL (см. документация), и это может быть очень удобно. Например, вы можете удалить все строки из 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

Ответ 2

Я знаю, вы спрашиваете, как вы можете решить свою проблему, используя инструкцию WITH, и получили хороший ответ. Но я предлагаю взглянуть на альтернативы в том же вопросе, который вы связали.

Как насчет этого?

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

Ответ 3

Для меня это сработало Как в 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);