朋友们,在我们写SQL更新语句时,经常需要基于一个表的值对另一个表进行匹配更新。这种更新方式与直接赋值类的更新不同,写法也会复杂一些,下面我基于实例说明多表匹配更新的常规写法和可能碰到的问题。
多表匹配更新的语法结构
我见过最多的是两种方式,一种方式是直接源于多表,通过where条件匹配的,语法大致如下:
update t1 set t1.字段=t2.字段 from 表1 t1, 表2 t2 where 表之间的匹配条件
这种写法我用的不多,可能是我平时建表总存在各种关联,我比较习惯通过join方式匹配的方式,语法大致如下:
update t1 set t1.字段=t2.字段 from 表1 t1 inner join 表2 t2 on t1.字段=t2.字段 where 其它条件
我觉得第二种写法更加直观,更便于将两个表的关系暴露出来。我下面就以第二种方式为例,具体说说多表更新的做法。
准备数据
我通过两个表变量进行演示,创建和初始化数据的SQL脚本如下:
declare @t1 table(FID int identity(1,1), FName varchar(100),FSerial int) declare @t2 table(FSerial int identity(1,1), FName varchar(100), FID int) insert into @t1(FName) values('马云') insert into @t1(FName) values('马化腾') insert into @t1(FName) values('马云') insert into @t1(FName) values('李彦宏') insert into @t1(FName) values('马云') insert into @t1(FName) values('刘强东') insert into @t1(FName) values('马云') select * from @t1 insert into @t2(FName) values('马云') select * from @t2
数据展示如下:
单条匹配多表更新的具体写法
所谓单条匹配,就是待修改表的数据,只与条件匹配表实现一对一或多对一的关系。为什么我这里要分开说,等您看下一段落的时候就知道了。
针对表变量@t1和@t2,比如我们要更新@t1中的FSerial的值,条件是根据@t2中的FName与@t1中的FName相同,显然@t1中的所有FName为“马云”的都会被更新成“1”,而FName为“马化腾”、“李彦宏”和“刘强东”的都无法匹配到。脚本写法如下:
...上面的定义和初始化脚本省略 update t1 set t1.FSerial=t2.FSerial from @t1 t1 inner join @t2 t2 on t1.FName=t2.FName select * from @t1
执行的结果确实如此,参看下图:
多条匹配多表更新的隐藏问题
还是基于上面的例子,如果我们把要更新的对象倒转,使用@t1的数据来更新@t2表的数据,这时候问题就来了,在表@t1中,有多条叫做“马云”的记录,如果我们把@t1的FID基于FName相同的条件更新到@t2的FID,到底那一条叫做“马云”的记录对应的FID会被更新过去呢?
先上代码:
...上面的定义和初始化脚本省略 update t2 set t2.FID=t1.FID from @t2 t2 inner join @t1 t1 on t2.FName=t1.FName select * from @t2
执行的结果可能是您未想到的:
通过上图您可以看出,当存在多条,正常排序的最后一条匹配记录值被更新过去了。
这或许至少就是SQL Server内部的逻辑,写多了就成了经验,知道就行了,内部的逻辑也不好深入探究。
希望对您有所帮助!