我们可以在更新语句中减少两个子查询之间的冗余吗?

时间:2018-06-24 19:34:11

标签: sql postgresql

来自数据库系统概念

  

假设我们有一个关系funds_received(dept_name,金额)   存储每个接收的资金(例如,通过电子资金转帐)   一组部门。现在假设我们要将金额加到   相应部门预算的余额。为了使用   要执行此任务的SQL更新语句,我们必须执行   查找每个元组中的已收资金关系   部门关系。我们可以在update子句中使用子查询来   请执行以下任务:为简单起见,我们假设   每个收到的关系基金最多包含一个元组   部门。

update department set budget = budget +
(select amount
from funds_received
where funds_received.dept_name = department.dept_name)
where exists(
select *
from funds_received
where funds_received.dept_name = department.dept_name);
     

请注意,更新的where子句中的条件可确保   仅更新收到的资金中具有相应元组的帐户,   而set子句中的子查询计算的金额为   添加到每个这样的部门。

我想知道为什么我们需要where子句来首先检查部门是否收到任何资金?

这两个子查询基本相同,并且看起来很多余。

没有where子句的以下内容不能相同吗?

 update department set budget = budget +
 (select amount
 from funds_received
 where funds_received.dept_name = department.dept_name)

如果一个部门没有任何收到的资金,那么amount将为空,而budge + ...将不起作用?

我对SQL标准或PostgreSQL中的解决方案感兴趣。

谢谢。

2 个答案:

答案 0 :(得分:2)

如果没有匹配项,则需要where子句。如果是这样,则set条件(按书面规定)将返回NULL-可能是一件坏事。

但是Postgres使用from有更好的解决方案:

update department d
    set budget = d.budget + fr.amount
from funds_received fr
where fr.dept_name = d.dept_name;

答案 1 :(得分:1)

例如,如果处理WHERE,则可能会留下外部NULL子句。与coalesce()

UPDATE department
       SET budget = budget
                    +
                    coalesce((SELECT amount
                                     FROM funds_received
                                     WHERE funds_received.dept_name = department.dept_name), 0);

这可以确保,如果一个部门没有收到任何资金,则不会返回NULL,这也可能使附加收益NULL(这可能取决于DBMS,在这种情况下会发生什么)一件事)。 coalesce()会将NULL变成0,这是添加的中性元素,因此预算保持不变。

(假设funds_received.amount永远不会是NULL。如果它是NULL,则coalesce()无法“知道”,如果NULL在那儿是因为没有找到记录,或者因为amount实际上是NULL。如果amount实际上是NULL,则原始查询会将NULL添加到预算中,我的查询将添加一个0。因此在这种情况下,查询是不等效的,但是我认为这本书的作者很有可能对NOT NULL施加了这样一个隐含的funds_received.amount约束记住。)

但是,另一方面,WHERE子句可能会减少必须更新的行(即使更新实际上并没有改变值,也需要对行进行读写)和因此可以提高性能。