基于集合的方法来更新多个表,而不是 WHILE 循环?
Set-based approach to updating multiple tables, rather than a WHILE loop?
显然我太习惯过程式编程了,我不知道如何使用基于集合的方法来处理这个问题。
我在 SQL 服务器中有几个临时 table,每个都有数千条记录。其中一些每个都有数万条记录,但它们都是记录集的一部分。我基本上加载了一堆 xml 数据,如下所示:
<root>
<entry>
<id-number>12345678</id-number>
<col1>blah</col1>
<col2>heh</col2>
<more-information>
<col1>werr</col1>
<col2>pop</col2>
<col3>test</col3>
</more-information>
<even-more-information>
<col1>czxn</col1>
<col2>asd</col2>
<col3>yyuy</col3>
<col4>moat</col4>
</even-more-information>
<even-more-information>
<col1>uioi</col1>
<col2>qwe</col2>
<col3>rtyu</col3>
<col4>poiu</col4>
</even-more-information>
</entry>
<entry>
<id-number>12345679</id-number>
<col1>bleh</col1>
<col2>sup</col2>
<more-information>
<col1>rrew</col1>
<col2>top</col2>
<col3>nest</col3>
</more-information>
<more-information>
<col1>234k</col1>
<col2>fftw</col2>
<col3>west</col3>
</more-information>
<even-more-information>
<col1>asdj</col1>
<col2>dsa</col2>
<col3>mnbb</col3>
<col4>boat</col4>
</even-more-information>
</entry>
</root>
这里简要展示了临时 table 的样子:
临时Table1(条目):
+------------+--------+--------+
| UniqueID | col1 | col2 |
+------------+--------+--------+
| 732013 | blah | heh |
| 732014 | bleh | sup |
+------------+--------+--------+
临时 Table 2(更多信息):
+------------+--------+--------+--------+
| UniqueID | col1 | col2 | col3 |
+------------+--------+--------+--------+
| 732013 | werr | pop | test |
| 732014 | rrew | top | nest |
| 732014 | 234k | ffw | west |
+------------+--------+--------+--------+
临时Table3(更多信息):
+------------+--------+--------+--------+--------+
| UniqueID | col1 | col2 | col3 | col4 |
+------------+--------+--------+--------+--------+
| 732013 | czxn | asd | yyuy | moat |
| 732013 | uioi | qwe | rtyu | poiu |
| 732014 | asdj | dsa | mnbb | boat |
+------------+--------+--------+--------+--------+
我正在从一个 XML 文件中加载这些数据,并且发现这是我可以分辨哪些信息属于哪条记录的唯一方法,因此每个临时 table 都有以下内容插入顶部:
T.value('../../id-number[1]', 'VARCHAR(8)') UniqueID,
如您所见,每个临时 table 都有一个 UniqueID
分配给它的特定记录,以表明它属于主记录。我在数据库中有大量项目,我想使用基于集合的方法更新每个非临时 table 中的每一列,但它必须受到 UniqueID
.[= 的限制28=]
在第一个以外的table中,有一个Foreign_ID
基于主table的PrimaryKey_ID
,而UniqueID
不会被插入...它只是为了帮助告诉什么去哪里。
这是我试图找出的确切逻辑:
如果id-number
当前存在于主table中,则根据主table的PrimaryKey_ID
号更新tables ],这与每个 table 的 Foreign_ID
中的数字完全相同。外键 table 的编号与 id-number
的编号完全不同——它们不一样。
如果id-number
不存在,则插入记录。我已经完成了这部分。
但是,我目前的想法是必须设置临时变量,例如@IDNumber
和@ForeignID
,然后循环遍历它。我不仅得到了多个结果而不是当前结果,而且每个人都说 WHILE
不应该使用,尤其是对于如此大量的数据。
如何使用基于集合的方法更新这些 table?
您可以使用 MERGE
在单个语句中执行更新插入(更新和插入)
首先将条目合并到主table
对于其他 tables,你可以与 main table 进行连接以获取外部 ID 映射
MERGE Table2 as Dest
USING ( select t2.*, m.primaryKey-Id as foreign_ID
from #tempTable2 t2
join mainTable m
on t2.id-number = m.id-number
) as Source
on Dest.Foreign_ID = m.foreign_ID
WHEN MATCHED
THEN Update SET Dest.COL1 = Source.Col1
WHEN NOT MATCHED then
INSERT (FOREGIN_ID, col1, col2,...)
values ( src.foreign_Id, src.col1, src.col2....)
假设您已经提取了此 XML,您可以执行类似于以下操作的操作:
UPDATE ent
SET ent.col1 = tmp1.col1,
ent.col2 = tmp1.col2
FROM dbo.[Entry] ent
INNER JOIN #TempEntry tmp1
ON tmp1.UniqueID = ent.UniqueID;
UPDATE mi
SET mi.col1 = tmp2.col1,
mi.col2 = tmp2.col2,
mi.col3 = tmp2.col3
FROM dbo.[MoreInformation] mi
INNER JOIN dbo.[Entry] ent -- mapping of Foreign_ID ->UniqueID
ON ent.PrimaryKey_ID = mi.Foreign_ID
INNER JOIN #TempMoreInfo tmp2
ON tmp2.UniqueID = ent.UniqueID
AND tmp2.SomeOtherField = mi.SomeOtherField; -- need 1 more field
UPDATE emi
SET ent.col1 = tmp3.col1,
emi.col2 = tmp3.col2,
emi.col3 = tmp3.col3,
emi.col4 = tmp3.col4
FROM dbo.[EvenMoreInformation] emi
INNER JOIN dbo.[Entry] ent -- mapping of Foreign_ID ->UniqueID
ON ent.PrimaryKey_ID = mi.Foreign_ID
INNER JOIN #TempEvenMoreInfo tmp3
ON tmp3.UniqueID = ent.UniqueID
AND tmp3.SomeOtherField = emi.SomeOtherField; -- need 1 more field
现在,我应该指出,如果目标真的是
update every single column in each non-temporary table
那么对于任何具有多个记录的子 table 存在一个概念问题。如果 table 中没有记录在 Foreign_ID
字段之外保持不变(我猜是 table 的主键?),那么你怎么知道哪一行是哪个更新?当然,你可以根据非临时Entry
table中已有的UniqueID
映射找到正确的Foreign_ID
,但至少需要有一个字段不是将用于查找确切行的 IDENTITY(或 UNIQUEIDENTIFIER
通过 NEWID
或 NEWSEQUENTIALID
填充)。
如果无法找到 stable 匹配字段,那么您别无选择,只能使用擦除和替换方法。
P.S。我曾经推荐 MERGE
命令,但由于了解了它的所有错误和问题而停止使用。 "nicer" 语法不值得潜在的问题。更多信息,请参阅Use Caution with SQL Server's MERGE Statement。
显然我太习惯过程式编程了,我不知道如何使用基于集合的方法来处理这个问题。
我在 SQL 服务器中有几个临时 table,每个都有数千条记录。其中一些每个都有数万条记录,但它们都是记录集的一部分。我基本上加载了一堆 xml 数据,如下所示:
<root>
<entry>
<id-number>12345678</id-number>
<col1>blah</col1>
<col2>heh</col2>
<more-information>
<col1>werr</col1>
<col2>pop</col2>
<col3>test</col3>
</more-information>
<even-more-information>
<col1>czxn</col1>
<col2>asd</col2>
<col3>yyuy</col3>
<col4>moat</col4>
</even-more-information>
<even-more-information>
<col1>uioi</col1>
<col2>qwe</col2>
<col3>rtyu</col3>
<col4>poiu</col4>
</even-more-information>
</entry>
<entry>
<id-number>12345679</id-number>
<col1>bleh</col1>
<col2>sup</col2>
<more-information>
<col1>rrew</col1>
<col2>top</col2>
<col3>nest</col3>
</more-information>
<more-information>
<col1>234k</col1>
<col2>fftw</col2>
<col3>west</col3>
</more-information>
<even-more-information>
<col1>asdj</col1>
<col2>dsa</col2>
<col3>mnbb</col3>
<col4>boat</col4>
</even-more-information>
</entry>
</root>
这里简要展示了临时 table 的样子:
临时Table1(条目):
+------------+--------+--------+
| UniqueID | col1 | col2 |
+------------+--------+--------+
| 732013 | blah | heh |
| 732014 | bleh | sup |
+------------+--------+--------+
临时 Table 2(更多信息):
+------------+--------+--------+--------+
| UniqueID | col1 | col2 | col3 |
+------------+--------+--------+--------+
| 732013 | werr | pop | test |
| 732014 | rrew | top | nest |
| 732014 | 234k | ffw | west |
+------------+--------+--------+--------+
临时Table3(更多信息):
+------------+--------+--------+--------+--------+
| UniqueID | col1 | col2 | col3 | col4 |
+------------+--------+--------+--------+--------+
| 732013 | czxn | asd | yyuy | moat |
| 732013 | uioi | qwe | rtyu | poiu |
| 732014 | asdj | dsa | mnbb | boat |
+------------+--------+--------+--------+--------+
我正在从一个 XML 文件中加载这些数据,并且发现这是我可以分辨哪些信息属于哪条记录的唯一方法,因此每个临时 table 都有以下内容插入顶部:
T.value('../../id-number[1]', 'VARCHAR(8)') UniqueID,
如您所见,每个临时 table 都有一个 UniqueID
分配给它的特定记录,以表明它属于主记录。我在数据库中有大量项目,我想使用基于集合的方法更新每个非临时 table 中的每一列,但它必须受到 UniqueID
.[= 的限制28=]
在第一个以外的table中,有一个Foreign_ID
基于主table的PrimaryKey_ID
,而UniqueID
不会被插入...它只是为了帮助告诉什么去哪里。
这是我试图找出的确切逻辑:
如果
id-number
当前存在于主table中,则根据主table的PrimaryKey_ID
号更新tables ],这与每个 table 的Foreign_ID
中的数字完全相同。外键 table 的编号与id-number
的编号完全不同——它们不一样。如果
id-number
不存在,则插入记录。我已经完成了这部分。
但是,我目前的想法是必须设置临时变量,例如@IDNumber
和@ForeignID
,然后循环遍历它。我不仅得到了多个结果而不是当前结果,而且每个人都说 WHILE
不应该使用,尤其是对于如此大量的数据。
如何使用基于集合的方法更新这些 table?
您可以使用 MERGE
在单个语句中执行更新插入(更新和插入)
首先将条目合并到主table
对于其他 tables,你可以与 main table 进行连接以获取外部 ID 映射
MERGE Table2 as Dest
USING ( select t2.*, m.primaryKey-Id as foreign_ID
from #tempTable2 t2
join mainTable m
on t2.id-number = m.id-number
) as Source
on Dest.Foreign_ID = m.foreign_ID
WHEN MATCHED
THEN Update SET Dest.COL1 = Source.Col1
WHEN NOT MATCHED then
INSERT (FOREGIN_ID, col1, col2,...)
values ( src.foreign_Id, src.col1, src.col2....)
假设您已经提取了此 XML,您可以执行类似于以下操作的操作:
UPDATE ent
SET ent.col1 = tmp1.col1,
ent.col2 = tmp1.col2
FROM dbo.[Entry] ent
INNER JOIN #TempEntry tmp1
ON tmp1.UniqueID = ent.UniqueID;
UPDATE mi
SET mi.col1 = tmp2.col1,
mi.col2 = tmp2.col2,
mi.col3 = tmp2.col3
FROM dbo.[MoreInformation] mi
INNER JOIN dbo.[Entry] ent -- mapping of Foreign_ID ->UniqueID
ON ent.PrimaryKey_ID = mi.Foreign_ID
INNER JOIN #TempMoreInfo tmp2
ON tmp2.UniqueID = ent.UniqueID
AND tmp2.SomeOtherField = mi.SomeOtherField; -- need 1 more field
UPDATE emi
SET ent.col1 = tmp3.col1,
emi.col2 = tmp3.col2,
emi.col3 = tmp3.col3,
emi.col4 = tmp3.col4
FROM dbo.[EvenMoreInformation] emi
INNER JOIN dbo.[Entry] ent -- mapping of Foreign_ID ->UniqueID
ON ent.PrimaryKey_ID = mi.Foreign_ID
INNER JOIN #TempEvenMoreInfo tmp3
ON tmp3.UniqueID = ent.UniqueID
AND tmp3.SomeOtherField = emi.SomeOtherField; -- need 1 more field
现在,我应该指出,如果目标真的是
update every single column in each non-temporary table
那么对于任何具有多个记录的子 table 存在一个概念问题。如果 table 中没有记录在 Foreign_ID
字段之外保持不变(我猜是 table 的主键?),那么你怎么知道哪一行是哪个更新?当然,你可以根据非临时Entry
table中已有的UniqueID
映射找到正确的Foreign_ID
,但至少需要有一个字段不是将用于查找确切行的 IDENTITY(或 UNIQUEIDENTIFIER
通过 NEWID
或 NEWSEQUENTIALID
填充)。
如果无法找到 stable 匹配字段,那么您别无选择,只能使用擦除和替换方法。
P.S。我曾经推荐 MERGE
命令,但由于了解了它的所有错误和问题而停止使用。 "nicer" 语法不值得潜在的问题。更多信息,请参阅Use Caution with SQL Server's MERGE Statement。