小编典典

在以下语句完成之前,不提交CTE删除

sql

我遇到的问题是,删除的数据稍后仍会出现在同一查询中。自然,在完全独立的查询中,不会显示已删除的数据。

这不是我的用例,但是我认为这是显示问题的最简单方法:

CREATE TABLE company (id INT PRIMARY KEY, name TEXT);
CREATE TABLE employee (id INT PRIMARY KEY, company_id INT REFERENCES company(id), name TEXT);

INSERT INTO company VALUES (1, 'first company');
INSERT INTO company VALUES (2, 'second company');

INSERT INTO employee VALUES (1, 1, 'first employee');
INSERT INTO employee VALUES (2, 2, 'second employee');

-- this select can successfully query for the data which has just been deleted
WITH deleted_employee AS (DELETE FROM employee WHERE id = 1 RETURNING id)
SELECT id, name FROM employee JOIN deleted_employee USING (id);

-- this select shows it has been deleted
SELECT * FROM employee;

我把它放在这里了

DELETE在整个查询完成之前,似乎没有提交正义,这感觉很奇怪,因为优先级要求DELETE发生在之前SELECT

有什么方法可以在单个查询中实现此目标吗?


编辑

答案已经回答了直接的问题。根本的问题是,如果没有更多与该公司关联的员工,则删除该员工然后删除其关联的公司。

这是我可以解决的查询:

WITH affected_company AS (DELETE FROM employee WHERE id = 1 RETURNING company_id)
DELETE FROM company
USING affected_company
WHERE NOT EXISTS (
  SELECT 1
  FROM employee
  WHERE company_id = affected_company.company_id
);

SELECT * FROM company;
SELECT * FROM employee;

和更新的小提琴

您可以看到该公司没有被删除。


阅读 166

收藏
2021-04-28

共1个答案

小编典典

这是预期的并有文件记录。

引用手册

WITH中的子语句彼此并与主查询并发执行。因此,在WITH中使用数据修改语句时,指定更新实际发生的顺序是不可预测的。所有语句都使用相同的快照执行(请参见第13章),
因此它们不能“彼此”影响目标表 。这减轻了行更新实际顺序的不可预测性的影响,并且意味着RETURNING数据
是在不同的WITH子语句与主查询之间传递更改的唯一途径

(强调我的)


可以 使用链接的CTE删除公司:

with deleted_emp as (
  delete from employee 
  where id = 1 
  returning company_id, id as employee_id
)
delete from company
where id in (select company_id from deleted_emp) 
  and not exists (select * 
                  from employee e
                     join deleted_emp af 
                       on af.company_id = e.company_id 
                      and e.id <> af.employee_id)

重要的是从not exists子查询中排除刚删除的员工,因为这在第二个delete语句中始终可见,因此不存在永远不会为真。因此,子查询从本质上检查是否存在除分配给同一公司的已删除员工以外的其他员工。

在线示例:https//rextester.com/IVZ78695

2021-04-28