基于集合的方法来更新多个表,而不是 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不会被插入...它只是为了帮助告诉什么去哪里。

这是我试图找出的确切逻辑:

  1. 如果id-number当前存在于主table中,则根据主table的PrimaryKey_ID号更新tables ],这与每个 table 的 Foreign_ID 中的数字完全相同。外键 table 的编号与 id-number 的编号完全不同——它们不一样。

  2. 如果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 的主键?),那么你怎么知道哪一行是哪个更新?当然,你可以根据非临时Entrytable中已有的UniqueID映射找到正确的Foreign_ID,但至少需要有一个字段不是将用于查找确切行的 IDENTITY(或 UNIQUEIDENTIFIER 通过 NEWIDNEWSEQUENTIALID 填充)。

如果无法找到 stable 匹配字段,那么您别无选择,只能使用擦除和替换方法。

P.S。我曾经推荐 MERGE 命令,但由于了解了它的所有错误和问题而停止使用。 "nicer" 语法不值得潜在的问题。更多信息,请参阅Use Caution with SQL Server's MERGE Statement