UPDATE FROM WHERE和UPDATE FROM INNER JOIN有什么区别?

时间:2014-05-14 23:08:26

标签: sql sql-server

DECLARE @DATA TABLE
(
    Id int,
    Value int
)
INSERT INTO @DATA VALUES (1, 10)
INSERT INTO @DATA VALUES (2, 20)
INSERT INTO @DATA VALUES (3, 30)
INSERT INTO @DATA VALUES (4, 40)

DECLARE @TO_FILL TABLE
(
    Id int,
    Value int
)
INSERT INTO @TO_FILL VALUES (1, 100)
INSERT INTO @TO_FILL VALUES (3, 300)

DECLARE @METHOD int = 0

IF @METHOD = 0
BEGIN
    UPDATE @DATA
    SET Value = source.Value
    FROM @TO_FILL source
    WHERE [@DATA].Id = source.Id
END
ELSE
BEGIN
    UPDATE @DATA
    SET Value = source.Value
    FROM @DATA destination
    INNER JOIN @TO_FILL source ON destination.Id = source.Id
END

SELECT *
FROM @DATA

想法是每当id匹配时用@TO_FILL中的值更新表@DATA。无论@METHOD是否设置为0,此查询都将提供相同的结果。

我可以理解使用WHERE子句的块背后的逻辑,它将是:

  • 更新表@DATA
  • 对于每一行,修改列值
  • 使用表@TO_FILL,别名源
  • 中的列值
  • 每当列ID匹配
  • 时进行修改

但是我很难弄清楚第二个块背后的原因,它使用了INNER JOIN子句。在我看来,表有三个“临时实例”:@ DATA,@ DATA别名目的地,@ TO_FILL别名源。正在连接目标和源以确定必须修改的行集(让我们称之为@DATA_TO_FILL),但我看不到它是如何链接到第一个表(@DATA)的。由于@DATA和@DATA_TO_FILL之间没有WHERE或INNER JOIN子句,它是如何工作的?

3 个答案:

答案 0 :(得分:3)

两个查询基本上都在做同样的事情,区别在于语法。

第一次查询

它正在使用旧的连接语法,其中在where子句中提到了连接条件...

SELECT *
FROM table1 , Table2
WHERE Table1.ID = Table2.ID

第二次查询

你的第二个块使用更新的ansi连接语法,使用了关键字JOIN,并在ON子句中提到了连接条件,就像这样......

SELECT *
FROM table1 INNER JOIN Table2
ON Table1.ID = Table2.ID

两个查询的结果集相同但只有语法差异,第二种方法是首选语法。坚持下去。

答案 1 :(得分:2)

来自相关的TechNet page

  

如果要更新的对象与FROM子句中的对象相同,并且FROM子句中只有一个对象的引用,则可能指定也可能不指定对象别名。如果正在更新的对象在FROM子句中出现多次,则对该对象的一个​​且仅一个引用不得指定表别名。 FROM子句中对象的所有其他引用都必须包含对象别名。

换句话说,在您的示例中,在FROM子句中为@DATA分配别名这一事实并不会阻止SQL Server识别它与您正在更新的表相同,因为没有歧义。但是,如果您的FROM子句涉及将@DATA连接到自身,那么您必须通过从一个实例中省略别名来指定要更新的表。

答案 2 :(得分:-1)

结合上面的两个答案:

首先使用WHERE加入表格或INNER JOIN没有区别,除了WHERE语法较旧而INNER JOIN是较新的语法,你应该养成习惯使用。

其次不要被第二个SQL中的FROM @DATA destination搞糊涂。唯一的目的是为@DATA提供destination的别名。就是这样。

写这篇文章的人出于某种原因使用了完全不同的语法来完成同样的事情。

我个人更喜欢第二种方式,因为:

- 使用INNER JOIN代替WHERE

- 为目标表分配一个别名,使查询更容易理解。