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子句的块背后的逻辑,它将是:- 更新数据表
- 对于每一行,修改列值
- 使用来自表@TO_FILL的列值,别名源
- 当两个列Id匹配时进行修改
但是我很难弄清楚第二个块背后的原因,它使用了INNER JOIN子句。在我看来,表有三个"临时实例":@DATA, @DATA别名目的,@TO_FILL别名源。目标和源被连接起来,以确定必须修改的行集(让我们称之为@DATA_TO_FILL),但是我看不出它是如何链接到第一个表(@DATA)的。既然@DATA和@DATA_TO_FILL之间没有WHERE或INNER JOIN子句,那么它是如何工作的呢?
两个查询本质上是做同样的事情,不同的是语法。
1日查询
它使用旧的连接语法,在where子句中提到连接条件,就像这样…
SELECT *
FROM table1 , Table2
WHERE Table1.ID = Table2.ID
2号查询
你的第二个块使用较新的ansi连接语法,使用关键字JOIN
,并且在ON
子句中提到连接条件,类似于.....
SELECT *
FROM table1 INNER JOIN Table2
ON Table1.ID = Table2.ID
两个查询的结果集是相同的,只是语法不同,第二种方法是首选的语法。坚持下去。
从相关的TechNet页面:
如果要更新的对象与FROM子句中的对象相同,并且在FROM子句中对该对象只有一个引用,则可以指定对象别名,也可以不指定对象别名。如果要更新的对象在FROM子句中出现多次,则对该对象的一个且只有一个引用不得指定表别名。FROM子句中对对象的所有其他引用必须包含对象别名。
换句话说,在你的例子中,你在FROM子句中给@DATA分配别名的事实并不妨碍SQL Server识别出它是你正在更新的同一个表,因为没有歧义。但是,如果FROM子句涉及到将@DATA连接到自身,则必须通过从一个实例中省略别名来指定要更新的表。
结合以上两个答案:
首先,使用WHERE
连接表和INNER JOIN
没有区别,除了WHERE
是较旧的语法,INNER JOIN
是较新的语法,你应该养成使用的习惯。
其次,不要被第二个SQL中的FROM @DATA destination
所迷惑。它的唯一目的是给@DATA
一个destination
的别名。就是这样。
写这篇文章的人出于某种原因使用了完全不同的语法来做完全相同的事情。
我个人更喜欢第二种方式,因为:
-使用INNER JOIN
代替WHERE
-为目标表分配一个别名,使查询更容易理解。