postgresql UPDATE的FROM端如何与UPDATE的目标表相关?

vs3odd8k  于 2023-08-04  发布在  PostgreSQL
关注(0)|答案(2)|浏览(207)

下面的查询(来源于此处Postgres SQL SELECT and UPDATE behaving differently

update fromemailaddress
    set call = true 
    from email
    where email.fromemailaddress = fromemailaddress.fromemailaddress and
          LOWER(email.subject) ~ 'tester';

字符串
我读它的方式是:

Line 1: update fromemailaddress


--我们告诉数据库我们正在更新fromemailaddress表

Line 2:        set call = true


--我们告诉数据库,名为“call”的字段将被设置为true

Line 3:        from email
Line 4:         where email.fromemailaddress = fromemailaddress.fromemailaddress and
Line 5:              LOWER(email.subject) ~ 'tester';


--好吧,现在事情越来越模糊了。这里到底发生了什么?数据库似乎以某种方式获取了第3、4和5行中的查询结果,但这如何告诉它要更新fromemailaddress表中的哪些行呢?什么是伪码?是不是类似于:

for each row in (query from lines 3, 4, 5)
    set call=true?


我只是看不出SQL更新的FROM端与另一端有什么关系。
最新消息:
按照下面@Erwin的回答中有价值的链接,我可以找到这些信息,这些信息触及了我试图理解的核心:
http://www.postgresql.org/docs/current/interactive/sql-update.html
当FROM子句存在时,实际上发生的情况是将目标表联接到from_list中提到的表,并且联接的每个输出行都表示目标表的一个更新操作。使用FROM时,应确保联接为要修改的每一行最多生成一个输出行。换句话说,目标行不应联接到其他表中的多个行。如果是这样,则只有一个联接行将用于更新目标行,但是将使用哪一个联接行并不容易预测。
由于这种不确定性,仅在子选择中引用其他表更安全,尽管通常比使用连接更难读取且速度更慢。

cqoc49vn

cqoc49vn1#

您显示的UPDATE查询与以下内容完全相同:

UPDATE fromemailaddress f
SET    call = true 
FROM  (
   SELECT fromemailaddress
   FROM   email 
   WHERE  subject ILIKE '%tester%'
   ) e
WHERE  e.fromemailaddress = f.fromemailaddress;

字符串
subject ILIKE '%tester%'subject ~ 'tester'的更快等价物。有关LIKEILIKE和正则表达式匹配(~in the manual的详细信息,请参阅dba.SE上的相关答案:

和 * 有效地 * 相同:

UPDATE fromemailaddress f
SET    call = true
WHERE  EXISTS (
   SELECT FROM email e
   WHERE  e.fromemailaddress = f.fromemailaddress
   AND    e.subject ILIKE '%tester%'
   );


用这个代替。
如果表email中有多行具有相同的fromemailaddress匹配fromemailaddress中的一行,则此表单每行只执行***一次***更新,不像您不幸的原始表单。
不要被这里使用fromemailaddress作为列和表名的事实所迷惑。
仔细阅读手册herehere。特别是这一位:

  • from_list*

表表达式的列表,允许其他表中的列出现在WHERE条件和更新表达式中。这类似于可以在SELECT语句的FROM子句中指定的表列表。请注意,目标表不能出现在***from_list***中,除非您打算进行自联接(在这种情况下,它必须以别名出现在***from_list***中)。

m0rkklqb

m0rkklqb2#

这是一个内部连接。仅在email.fromemailaddress = fromemailaddress.fromemailaddress处更新记录。如果不是一对一的关系,那么email中的一条记录将更新fromemailaddress中的多条记录,或者email中的许多记录将更新fromemailaddress中的单个记录。
前者就好了。我相信,如果你从源表中写入一个值,后者是不确定的。没有保证的结果,因为查询没有定义顺序。它将以查询引擎选择的任何顺序执行。举例来说:

update fromemailaddress
set call = email.call
from email
where email.fromemailaddress = fromemailaddress.fromemailaddress and
      LOWER(email.subject) ~ 'tester';

字符串
现在,如果email/fromemailaddress关系是多对一的,那么您可能会遇到问题。
由于这个特定的查询总是将值设置为静态值,因此不存在确定性问题。

相关问题