【问题标题】:How to update records with multiple tables linked by a foreign key using XQuery (or OPENXML) in SQL Server?如何使用 SQL Server 中的 XQuery(或 OPENXML)更新由外键链接的多个表的记录?
【发布时间】:2014-12-30 23:02:07
【问题描述】:

我有这样的 T-SQL 代码:

DECLARE @xml XML = (SELECT  CONVERT(xml, BulkColumn, 2) FROM OPENROWSET(Bulk 'C:\test.xml', SINGLE_BLOB) [blah])

-- Data for Table 1
SELECT
    ES.value('id-number[1]', 'VARCHAR(8)') IDNumber,
    ES.value('name[1]', 'VARCHAR(8)') Name,
    ES.value('date[1]', 'VARCHAR(8)') Date,
    ES.value('test[1]', 'VARCHAR(3)') Test,
    ES.value('testing[1]', 'VARCHAR(511)') Testing,
    ES.value('testingest[1]', 'VARCHAR(5)') Testingest
FROM @xml.nodes('xmlnodes/path') AS EfficiencyStatement(ES)

-- Data for Table 2
SELECT
    U.value('fork[1]', 'VARCHAR(8)') Fork,
    U.value('spoon[1]', 'VARCHAR(3)') Spoon,
    U.value('spork[1]', 'VARCHAR(3)') Spork,
FROM @xml.nodes('xmlnodes/path/nextpath') AS Utensils(U)

现在,我已经尝试了我通常使用的以及其他变体,例如:

AS XML ON xml.[id-number] = [table1].[id-number]

郑重声明,id-number 在整个文档中是唯一的。它永远不会再发生。

这对于从我的 XML 文件中获取数据很有用,但是参照完整性为零。如何确保表 2(及以上)在插入时保持引用完整性?

这应该是一个更好的解释

  1. 我想从文件中加载 XML 值。对于INSERT,我可以毫无问题地使用OPENXML,并在最后使用AS XML ON xml.[id-number] = [table1].[id-number] 根据id 号绑定它。
  2. 我想使用UPDATEMERGE 或其他东西来更新数据库记录(包括所有链接的表及其列)——任何东西!为此,我相信我需要找到一种方法来根据每个表中存在的Foreign_ID 值来维护引用完整性。有几十个表都通过Foreign_ID链接,那么我如何更新所有这些?

表格示例

  Table #1
+-------------+-----------+-----------+------------+---------+-----------+------------+
| Primary_Key | ID_Number |    Name   |    Date    |   Test  |  Testing  | Testingest |
+-------------+-----------+-----------+------------+---------+-----------+------------|
|   70001     |   12345   |   Tom     |  01/21/14  |   Hi    |    Yep    | Of course! |
|   70002     |   12346   |   Dick    |  02/22/14  |   Bye   |    No     | Never!     |
|   70003     |   12347   |   Harry   |  03/23/14  |   Sup   |    Dunno  | Same.      |
+----^--------+-----------+-----------+------------+---------+-----------+------------+
     |
     |-----------------|
                       |    
  Table #2             | Linked to primary key in the first table. 
+-------------+--------v--------+-------------+-------------+------------+
| Primary_Key |    Foreign_ID   |     Fork    |    Spoon    |    Spork   | 
+-------------+-----------------+-------------+-------------+------------+
|   0001      |     70001       |     Yes     |     No      |     No     |
|   0002      |     70002       |     No      |     Yes     |     No     |
|   0003      |     70003       |     No      |     No      |     Yes    |
+-------------+-----------------+-------------+-------------+------------+

插入之后,我需要能够UPDATE XML 文件中的表和列。经过大量研究,我无法弄清楚如何更新Foreign_ID 链接的每个表的值同时保持参照完整性。这意味着我在其他表中插入了错误的数据。

我想要更新正确的数据。为了正确更新它,我需要确保 XQuery 匹配正确的数据。有些表有多个字段对应一个特定的 Foreign_ID。

这是我正在使用的代码:

DECLARE @xml XML = (SELECT  CONVERT(xml, BulkColumn, 2) FROM OPENROWSET(Bulk 'C:\test.xml', SINGLE_BLOB) [blah])

-- Data for Table 1
SELECT
    ES.value('id-number[1]', 'VARCHAR(8)') IDNumber,
    ES.value('name[1]', 'VARCHAR(8)') Name,
    ES.value('date[1]', 'VARCHAR(8)') Date,
    ES.value('test[1]', 'VARCHAR(3)') Test,
    ES.value('testing[1]', 'VARCHAR(511)') Testing,
    ES.value('testingest[1]', 'VARCHAR(5)') Testingest
INTO #TempTable
FROM @xml.nodes('xmlnodes/path') AS EfficiencyStatement(ES)


-- @Serial Error: Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
SET @IDNumber = (SELECT SerialNumber from #TempTable)


SET @Foreign_ID = (SELECT [Foreign_ID] from [table] WHERE [id-number] = @IDNumber)


MERGE dbo.[table1] AS CF
USING (SELECT IDNumber, Name, Date, Test, Testing, Testingest FROM #TempTable) AS src
ON CF.[id-number] = src.IDNumber
-- ID-Number is unique, and is used to setup the initial referential integrity. Foreign_ID does not exist in the XML files, so we are not matching on that.

WHEN MATCHED THEN UPDATE
SET
   CF.[id-number] = src.IDNumber
   -- and so on...
WHEN NOT MATCHED THEN
-- Insert statements here
GO

这适用于第一个表。通过Foreign_ID 更新其他表时,它不会保持完整性。请注意,SET @Serial 有错误,但是当我将其设置为其他任何内容时,它会正确更新。

【问题讨论】:

标签: sql-server xml tsql sqlxml xquery-sql


【解决方案1】:

我不完全确定您在这里问的是什么,但是如果您不能使用建议的文章来强制在您的 XML 中进行引用,那么您实际上并没有一种仅在 XML 中执行此操作的后期方法。

对于 Table2+,您可以针对 TABLE 1 进行 EXISTS 检查并相应地进行处理(例如,参见 Referential integrity issue with Untyped XML in TSQL

我能想到的唯一其他方法是创建代表表 1、表 2...tableN 的架构的“真实”表,这些表具有相关的 FK 并插入其中。

【讨论】:

  • 我已更新问题以帮助您更好地理解它。
  • 仍有问题。你是什​​么意思“它不保持更新其他表的完整性”?它正在添加不应该在那里的行?您的数据如何通过 Foreign_ID 值知道哪个表需要更新/匹配?
  • 像这样:我将所有的 XML 加载到一个临时表中。然后我插入它,但我不知道它的顺序。它不会收集所有东西,是吗?我肯定只得到 1 个结果,而有时我应该得到 2 个或更多。这是一个示例:一个表有一个字段的多个结果,但是当我选择这些结果时,它们被无序排序......这意味着它将显示该表中的所有内容,但没有排序。我需要让它匹配一个 Foreign_ID id,所以我可以通过该 ID 选择来获取随附的记录。
  • 在Foreign_ID值相同的情况下,数据知道匹配哪个表需要更新。 Foreign_ID 值是从 INSERT 语句设置的,并且基于每个 XML 节点中存在的唯一 [id-number]。每个根中可能有一个父节点,或 400,000 个。我想我想代表一个节点并遍历它们。类似foreach (string[] parent in XmlNode) { Insert Record }
  • 我终于想通了,我会在写完其余部分后发布答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-08
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多