我有一个有帐号和卡号的数据库。我将这些匹配到一个文件,以将任何卡号更新为帐号,这样我只使用帐号。
我创建了一个将表链接到帐户/卡数据库的视图,以返回table ID和相关的帐号,现在我需要更新那些ID与account number匹配的记录。
这是Sales_Import表,其中的帐号字段需要更新:
LeadID |
AccountNumber |
147 |
5807811235 |
150 |
5807811326 |
185 |
7006100100007267039 |
这是RetrieveAccountNumber表,我需要从这里更新:
LeadID |
AccountNumber |
147 |
7006100100007266957 |
150 |
7006100100007267039 |
我尝试了下面的方法,但到目前为止运气都不佳:
UPDATE [Sales_Lead].[dbo].[Sales_Import]
SET [AccountNumber] = (SELECT RetrieveAccountNumber.AccountNumber
FROM RetrieveAccountNumber
WHERE [Sales_Lead].[dbo].[Sales_Import]. LeadID =
RetrieveAccountNumber.LeadID)
它将卡号更新为帐号,但是帐号被NULL替换
对于SQL Server 2008 +使用MERGE而不是专有的更新…FROM语法有一些吸引力。
它不仅是标准SQL,因此更易于移植,而且在源端有多个连接行的情况下(因此在更新中可能使用多个不同的值)也会引发错误,而不是最终结果不确定。
MERGE INTO Sales_Import
USING RetrieveAccountNumber
ON Sales_Import.LeadID = RetrieveAccountNumber.LeadID
WHEN MATCHED THEN
UPDATE
SET AccountNumber = RetrieveAccountNumber.AccountNumber;
然而,不幸的是,选择使用哪一种可能并不完全取决于首选的风格。SQL Server中MERGE的实现一直受到各种错误的困扰。Aaron Bertrand在这里整理了一份报告的清单。
在同一个表内更新:
DECLARE @TB1 TABLE
(
No Int
,Name NVarchar(50)
,linkNo int
)
DECLARE @TB2 TABLE
(
No Int
,Name NVarchar(50)
,linkNo int
)
INSERT INTO @TB1 VALUES(1,'changed person data', 0);
INSERT INTO @TB1 VALUES(2,'old linked data of person', 1);
INSERT INTO @TB2 SELECT * FROM @TB1 WHERE linkNo = 0
SELECT * FROM @TB1
SELECT * FROM @TB2
UPDATE @TB1
SET Name = T2.Name
FROM @TB1 T1
INNER JOIN @TB2 T2 ON T2.No = T1.linkNo
SELECT * FROM @TB1
下面的SQL有人建议,不工作在SQL Server。这个语法让我想起了我以前的学校类:
UPDATE table2
SET table2.col1 = table1.col1,
table2.col2 = table1.col2,
...
FROM table1, table2
WHERE table1.memberid = table2.memberid
不建议使用NOT IN或NOT EXISTS的所有其他查询。显示null是因为OP将整个数据集与较小的子集进行比较,当然会有匹配问题。这必须通过使用正确的JOIN编写正确的SQL来解决,而不是使用NOT IN来逃避问题。在这种情况下,使用NOT IN或NOT EXISTS可能会遇到其他问题。
我投票给最上面的,这是一种传统的方法,通过加入SQL Server来根据另一个表更新一个表。就像我说的,你不能在SQL Server的同一个UPDATE语句中使用两个表,除非你先连接它们。
我想再补充一点。
不要用相同的值更新一个值,这会产生额外的日志记录和不必要的开销。
参见下面的例子-尽管链接了3条记录,但它只会在2条记录上执行更新。
DROP TABLE #TMP1
DROP TABLE #TMP2
CREATE TABLE #TMP1(LeadID Int,AccountNumber NVarchar(50))
CREATE TABLE #TMP2(LeadID Int,AccountNumber NVarchar(50))
INSERT INTO #TMP1 VALUES
(147,'5807811235')
,(150,'5807811326')
,(185,'7006100100007267039');
INSERT INTO #TMP2 VALUES
(147,'7006100100007266957')
,(150,'7006100100007267039')
,(185,'7006100100007267039');
UPDATE A
SET A.AccountNumber = B.AccountNumber
FROM
#TMP1 A
INNER JOIN #TMP2 B
ON
A.LeadID = B.LeadID
WHERE
A.AccountNumber <> B.AccountNumber --DON'T OVERWRITE A VALUE WITH THE SAME VALUE
SELECT * FROM #TMP1
这是Mysql和Maria DB最简单和最好的
UPDATE table2, table1 SET table2.by_department = table1.department WHERE table1.id = table2.by_id
注意:如果您遇到以下错误基于您的Mysql/Maria DB版本“错误代码:1175。您正在使用安全更新模式,并且您试图更新一个没有使用KEY列的WHERE的表。要禁用安全模式,请切换首选项中的选项。
然后像这样运行代码
SET SQL_SAFE_UPDATES=0;
UPDATE table2, table1 SET table2.by_department = table1.department WHERE table1.id = table2.by_id
总结其他答案,关于如何仅在“匹配存在”时使用来自另一个表的数据更新目标表,有4种变体
查询和子查询:
update si
set si.AccountNumber = (
select ran.AccountNumber
from RetrieveAccountNumber ran
where si.LeadID = ran.LeadID
)
from Sales_Import si
where exists (select * from RetrieveAccountNumber ran where ran.LeadID = si.LeadID)
内连接:
update si
set si.AccountNumber = ran.AccountNumber
from Sales_Import si inner join RetrieveAccountNumber ran on si.LeadID = ran.LeadID
交叉连接:
update si
set si.AccountNumber = ran.AccountNumber
from Sales_Import si, RetrieveAccountNumber ran
where si.LeadID = ran.LeadID
走:
merge into Sales_Import si
using RetrieveAccountNumber ran on si.LeadID = ran.LeadID
when matched then update set si.accountnumber = ran.accountnumber;
所有的变体都是更少的琐碎和可以理解的,我个人更喜欢“内部连接”选项。但其中任何一种都可以使用,开发者必须根据自己的需求选择“更好的选项”
从性能的角度来看,使用join的变体更可取: