【问题标题】:How to delete records from CTE (Common Table Expression) in Postgres如何从 Postgres 中的 CTE(公用表表达式)中删除记录
【发布时间】:2021-03-02 20:59:30
【问题描述】:

我在 Postgres 中使用 CTE 编写了以下查询。现在我无法从中删除记录。

WITH cte AS (
    SELECT 
   
        firstname, 
        lastname, 
        country, 
        ROW_NUMBER() OVER (
            PARTITION BY 
                firstname, 
                lastname, 
                country
        ) row_num
     FROM 
        employee
) 
delete  from cte
where row_num >1

当我运行此查询时,它会显示错误:

关系“cte”不存在

这是我的表“员工”的示例

id  firstname  lastname  country
1   "Raj"      "Gupta"   "India"
2   "Raj"      "Gupta"   "India"
3   "Mohan"    "Kumar"   "USA"
4   "James"    "Barry"   "UK"
5   "James"    "Barry"   "UK"
6   "James"    "Barry"   "UK"

【问题讨论】:

  • 请提供员工表的样本数据。 :-)
  • @Linker 我已经编辑了我的问题并在其中添加了一个表员工示例。谢谢

标签: sql postgresql common-table-expression sql-delete


【解决方案1】:

无法从 CTE 中删除。

你可以这样做:

demo:db<>fiddle

DELETE FROM employee
WHERE id IN (
    SELECT
        id
    FROM (
        SELECT
            id,
            ROW_NUMBER() OVER (PARTITION BY firstname, lastname, country) row_num
        FROM 
            employee
    ) s
    WHERE row_num > 1
)

如果您仍然想使用 CTE,您可以将子查询合并为一个:

demo:db<>fiddle

WITH cte AS (
    SELECT
        id
    FROM (
        SELECT
            id,
            ROW_NUMBER() OVER (PARTITION BY firstname, lastname, country) row_num
        FROM 
            employee
    ) s
    WHERE row_num > 1
)
DELETE FROM employee
WHERE id IN (SELECT * FROM cte)

【讨论】:

    【解决方案2】:

    您不能从 postgresql 中的 CTE 表中删除记录。尽管在 SQLSERVER 等其他数据库服务器中也是可能的。 您可以查看 CTE 的 postgresql 文档。

    【讨论】:

    • 我发现这个sample for sqlserver 看起来就像 OP 正在做的事情
    • sql 标准对 cte 有什么看法?能否提供一些外部链接?
    【解决方案3】:

    我认为更好的情况是在创建 CTE 的步骤中过滤不需要的行(不删除)

    WITH cte AS (
        SELECT 
            firstname, 
            lastname, 
            country, 
            ROW_NUMBER() OVER (
                PARTITION BY 
                    firstname, 
                    lastname, 
                    country
            ) row_num
         FROM employee
         WHERE row_num >1
    )
    

    【讨论】:

      【解决方案4】:

      我建议使用:

      delete from employee e
          where e.id > (select min(e2.id)
                        from employee e2
                        where e2.firstname = e.firstname and
                              e2.lastname = e.lastname and 
                              e2.country = e.country
                       );
      

      这是标准 SQL,适用于 SQL Server 和 Postgres。

      与 SQL Server 版本的唯一区别是 NULL 值的处理方式。这会将它们都视为“不同”,因此匹配的 NULL 值不会被视为匹配。这可能不是您的数据中的问题,但您可以使用:

                        where e2.firstname is not distinct from e.firstname and
                              e2.lastname is not distinct from e.lastname and 
                              e2.country is not distinct from e.country
      

      如果您希望 NULL 值匹配。

      请注意,原始版本应该能够使用(lastname, firstname, country, id) 上的索引(在任一数据库中)。

      【讨论】:

        猜你喜欢
        • 2020-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多