左连接更新的行为

时间:2013-11-27 18:46:44

标签: mysql sql-update left-join mariadb

使用mysql 5.5,这样的语句:

update foo left join bar on foo.id=bar.id set foo.col='val', bar.col='val';
即使没有条形码,

似乎也会更新foo行(并且bar.col =不会生成任何错误或警告)。但据我所知,这在mysql文档中并不能保证。

任何人都可以在SQL标准或Oracle中提供权威参考,说明这是故意的吗?

它在其他SQL版本中是否有效,特别是 postgres和 MariaDB,或其他版本的mysql?

请注意,与上述不同,以下内容确实将左连接提升为内连接:

update foo left join bar on foo.id=bar.id set bar.col='val';

但这可能只是一种优化。

更新:澄清一下,我看到的行为是我想要的行为;我只是担心在我看来没有证件。如果我想要一个内连接,我会使用一个。

2 个答案:

答案 0 :(得分:2)

在PostgreSQL中,这种奇怪的语法简单无效。 UPDATE statement只能直接更改单个表中的数据(除了继承)。 你会改用:

UPDATE foo
SET    col = 'val'
FROM   bar
WHERE  foo.id = bar.id;

或者,由于您使用的是常量值,因此速度更快:

UPDATE foo
SET    col = 'val'
WHERE EXISTS (
   SELECT 1
   FROM   bar
   WHERE  foo.id = bar.id
   );

..它应该在任何的命名RDMS(MySQL,SQL Server,Oracle,...)中工作。

这些查询中的任何一个更新foo的行,其中bar中找到匹配项。通常,添加以下内容是明智的:

AND col IS DISTINCT FROM 'val'

或者:

AND col <> 'val'                  -- if involved values are NOT NULL

..以避免空更新。

答案 1 :(得分:0)

这是一个左连接,所以你所看到的是预期的。

  • A cross join B表示:每个A与每个B结合 - 就像笛卡尔积一样。

  • A inner join B,或简称为A join B,表示:每个A和B组合在一起,其中有一个A 一个B - 如,必需同时拥有A和B

  • A left join B表示:每个没有B的A,每个A和B组合在一个有A和B的地方 - 如, B可选。< / p>

  • A right join B相当于B left join A

  • A full join B表示:每个没有B的A,没有A的每个B,以及可以组合的每个A和B - 如A B可选。

http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html

您的第二个查询会更新与第一个查询相同的bar行。与第一个的唯一区别是您不再更新foo,因此您可能看不到相同的受影响行数。您只是在关联bar时才更新foo,但请注意,该查询仍会追溯foo与之无关联的bar行。

回答问题的其他部分:是的,其他数据库引擎的行为方式相同,提供或采取与Erwin强调的语法相关的化妆品。更新语句的要点相当于伪代码,其类似于:for each row in (select … from …) do stuffupdate table中的表是关联的select … from … [join …]语句中的第一个运行。