使用外键作为第一个表的标识列批量插入嵌套 xml

2023-12-04

我有一个 xml 如下:

<Records>
  <Record>
    <Name>Best of Pop</Name>
    <Studio>ABC studio</Studio>
    <Artists>
      <Artist>
        <ArtistName>John</ArtistName>
        <Age>36</Age>            
      </Artist> 
      <Artist>
        <ArtistName>Jessica</ArtistName>
        <Age>20</Age>            
      </Artist>
    </Artists>
  </Record>
  <Record>
    <Name>Nursery rhymes</Name>
    <Studio>XYZ studio</Studio>
    <Artists>
      <Artist>
        <ArtistName>Judy</ArtistName>
        <Age>10</Age>            
      </Artist> 
      <Artist>
        <ArtistName>Rachel</ArtistName>
        <Age>15</Age>            
      </Artist>
    </Artists>
  </Record>
</Records>

该文件可能包含数百万条记录。我的 MS SQL 数据库,运行于Azure SQL 数据库,有以下2个表来存储这些记录:

  1. Record(RecordId[PK,身份,自增],姓名,工作室)

  2. Artist(RecordId [外键指 Record.RecordId], ArtistName, Age)

是否可以批量插入记录Record表,获取RecordIds,然后将艺术家信息批量插入到Artist在单个表中使用xml节点遍历xml的方法?

我长期以来一直在寻找一种有效的方法来做到这一点,但徒劳无功。

我尝试过类似于所描述的方法here and here,但我无法找到解决方案。

任何指向解决方案方向的指针都会有很大帮助。

Update: @srutzky:感谢您的解决方案。这完全符合我的要求。但有一个问题。我必须使用节点方法来解决问题。我已经更改了查询的第一部分。但我陷入了下半场。这就是我所做的。

DECLARE @Record TABLE (RecordId INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
                       Name NVARCHAR(400) UNIQUE,
                       Studio NVARCHAR(400));
DECLARE @Artist TABLE (ArtistId INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
                       RecordId INT NOT NULL,
                       ArtistName NVARCHAR(400), Age INT);

INSERT INTO @Record (Name, Studio)
   SELECT  T.c.value(N'(Name/text())[1]', 'NVARCHAR(400)'),
           T.c.value(N'(Studio/text())[1]', 'NVARCHAR(400)')
 FROM @ImportData.nodes('/Records/Record') T(c);

SELECT * FROM @Record

你能帮我完成第二部分吗?我对这种 xml 处理方法很陌生。

UPDATE2:我明白了......我绞尽脑汁几个小时,尝试了一些方法,终于找到了解决方案。

DECLARE @Record TABLE (RecordId INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
                       Name NVARCHAR(400) UNIQUE,
                       Studio NVARCHAR(400));
DECLARE @Artist TABLE (ArtistId INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
                       RecordId INT NOT NULL,
                       ArtistName NVARCHAR(400), 
                       Age INT);

INSERT INTO @Record (Name, Studio)
   SELECT  T.c.value(N'(Name/text())[1]', 'NVARCHAR(400)'),
           T.c.value(N'(Studio/text())[1]', 'NVARCHAR(400)')
 FROM @ImportData.nodes('/Records/Record') T(c);

INSERT INTO @Artist (RecordId, ArtistName, Age)
    SELECT  (SELECT RecordId FROM @Record WHERE Name=T.c.value(N'(../../Name/text())[1]', 'NVARCHAR(400)')),
            T.c.value(N'(ArtistName/text())[1]', 'NVARCHAR(400)'),
           T.c.value(N'(Age/text())[1]', 'INT')
 FROM @ImportData.nodes('/Records/Record/Artists/Artist') T(c);

 SELECT * FROM @Record
 SELECT * FROM @Artist

@srutzky:非常感谢您为我指明了正确的方向。欢迎提出任何改进此解决方案的建议。


无论如何,这不能在一次传递中完成,因为您不能在同一个 DML 语句中插入两个表(好吧,在触发器和 OUTPUT 子句之外,这两者都没有帮助)。但它可以通过两次有效地完成。事实在<Name>内的元素<Record>唯一是关键,因为这使我们能够使用Record表作为第二遍的查找表(即当我们得到Artist rows).

首先,你需要(嗯,should) 创建一个UNIQUE INDEX on Record (Name ASC)。在下面的示例中,我使用的是UNIQUE CONSTRAINT,但这只是因为我使用表变量而不是临时表来使示例代码更容易重新运行(不需要在顶部显式 IF EXISTS DROP )。该索引将有助于第二遍的性能。

该示例使用 OPENXML,因为这很可能比使用.nodes()函数,因为同一个文档需要遍历两次。最后一个参数为OPENXML函数,则2,指定文档是“基于元素”的,因为默认解析正在查找“基于属性”。

DECLARE @DocumentID INT, @ImportData XML;

SET @ImportData = N'
<Records>
  <Record>
    <Name>Best of Pop</Name>
    <Studio>ABC studio</Studio>
    <Artists>
      <Artist>
        <ArtistName>John</ArtistName>
        <Age>36</Age>            
      </Artist> 
      <Artist>
        <ArtistName>Jessica</ArtistName>
        <Age>20</Age>            
      </Artist>
    </Artists>
  </Record>
  <Record>
    <Name>Nursery rhymes</Name>
    <Studio>XYZ studio</Studio>
    <Artists>
      <Artist>
        <ArtistName>Judy</ArtistName>
        <Age>10</Age>            
      </Artist> 
      <Artist>
        <ArtistName>Rachel</ArtistName>
        <Age>15</Age>            
      </Artist>
    </Artists>
  </Record>
</Records>';


DECLARE @Record TABLE (RecordId INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
                       Name NVARCHAR(400) UNIQUE,
                       Studio NVARCHAR(400));
DECLARE @Artist TABLE (ArtistId INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
                       RecordId INT NOT NULL,
                       ArtistName NVARCHAR(400), Age INT);

EXEC sp_xml_preparedocument @DocumentID OUTPUT, @ImportData;

-- First pass: extract "Record" rows
INSERT INTO @Record (Name, Studio)
   SELECT Name, Studio
   FROM   OPENXML (@DocumentID, N'/Records/Record', 2) 
             WITH (Name    NVARCHAR(400)  './Name/text()', 
                   Studio  NVARCHAR(400)  './Studio/text()');


-- Second pass: extract "Artist" rows
INSERT INTO @Artist (RecordId, ArtistName, Age)
   SELECT rec.RecordId, art.ArtistName, art.Age
   FROM   OPENXML (@DocumentID, N'/Records/Record/Artists/Artist', 2) 
             WITH (Name        NVARCHAR(400)  '../../Name/text()',
                   ArtistName  NVARCHAR(400)  './ArtistName/text()', 
                   Age         INT  './Age/text()') art
   INNER JOIN @Record rec
           ON rec.[Name] = art.[Name];


EXEC sp_xml_removedocument @DocumentID;
-------------------

SELECT * FROM @Record ORDER BY [RecordID];
SELECT * FROM @Artist ORDER BY [RecordID];

参考:

  • OPENXML
  • sp_xml_preparedocument
  • sp_xml_删除文档

EDIT:
随着新要求的使用.nodes()函数而不是OPENXML,以下内容将起作用:

DECLARE @ImportData XML;

SET @ImportData = N'
<Records>
  <Record>
    <Name>Best of Pop</Name>
    <Studio>ABC studio</Studio>
    <Artists>
      <Artist>
        <ArtistName>John</ArtistName>
        <Age>36</Age>            
      </Artist> 
      <Artist>
        <ArtistName>Jessica</ArtistName>
        <Age>20</Age>            
      </Artist>
    </Artists>
  </Record>
  <Record>
    <Name>Nursery rhymes</Name>
    <Studio>XYZ studio</Studio>
    <Artists>
      <Artist>
        <ArtistName>Judy</ArtistName>
        <Age>10</Age>            
      </Artist> 
      <Artist>
        <ArtistName>Rachel</ArtistName>
        <Age>15</Age>            
      </Artist>
    </Artists>
  </Record>
</Records>';

IF (OBJECT_ID('tempdb..#Record') IS NOT NULL)
BEGIN
   DROP TABLE #Record;
END;
IF (OBJECT_ID('tempdb..#Artist') IS NOT NULL)
BEGIN
   DROP TABLE #Artist;
END;

CREATE TABLE #Record (RecordId INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
                      Name NVARCHAR(400) UNIQUE,
                      Studio NVARCHAR(400));
CREATE TABLE #Artist (ArtistId INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
                      RecordId INT NOT NULL,
                      ArtistName NVARCHAR(400),
                      Age INT);


-- First pass: extract "Record" rows
INSERT INTO #Record (Name, Studio)
   SELECT col.value(N'(./Name/text())[1]', N'NVARCHAR(400)') AS [Name],
          col.value(N'(./Studio/text())[1]', N'NVARCHAR(400)') AS [Studio]
   FROM   @ImportData.nodes(N'/Records/Record') tab(col);


-- Second pass: extract "Artist" rows
;WITH artists AS
(
   SELECT col.value(N'(../../Name/text())[1]', N'NVARCHAR(400)') AS [RecordName],
          col.value(N'(./ArtistName/text())[1]', N'NVARCHAR(400)') AS [ArtistName],
          col.value(N'(./Age/text())[1]', N'INT') AS [Age]
   FROM   @ImportData.nodes(N'/Records/Record/Artists/Artist') tab(col)
)
INSERT INTO #Artist (RecordId, ArtistName, Age)
   SELECT rec.RecordId, art.ArtistName, art.Age
   FROM artists art
   INNER JOIN #Record rec
           ON rec.[Name] = art.RecordName;

-- OR --
-- INSERT INTO #Artist (RecordId, ArtistName, Age)
   SELECT rec.RecordId,
          col.value(N'(./ArtistName/text())[1]', N'NVARCHAR(400)') AS [ArtistName],
          col.value(N'(./Age/text())[1]', N'INT') AS [Age]
   FROM   @ImportData.nodes(N'/Records/Record/Artists/Artist') tab(col)
   INNER JOIN #Record rec
           ON rec.Name = col.value(N'(../../Name/text())[1]', N'NVARCHAR(400)');

-------------------

SELECT * FROM #Record ORDER BY [RecordID];
SELECT * FROM #Artist ORDER BY [RecordID];

有两个选项可以插入#Artist如上所示。第一个使用 CTE 将 XML 提取从 INSERT / SELECT 查询中抽象出来。另一个是简化版本,类似于您的查询UPDATE 2的问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用外键作为第一个表的标识列批量插入嵌套 xml 的相关文章

  • 在Excel VBA中将图像(jpg)转换为base64?

    我需要在 Excel 中转换图像 或通过VBA 转为base64 最后我将进行XML输出 我怎样才能做到这一点 我需要引用 DOM 吗 我一直在读书这个问题 https stackoverflow com questions 169907
  • 将 SQL Server 与 Dart 结合使用

    我还没有找到很好的答案 所以我想尝试一下得到答案 将 Microsoft SQL Server 与 Dart 结合使用的最佳方式是什么 我需要它能够从基本上任何操作系统 网络和移动设备上使用它 我觉得最好的方法可能是 GraphQL 但我对
  • 无法使用 Tedious 和 Node JS 连接到本地 SQL Server 数据库

    我正在尝试连接到本地计算机上的 SQL Server 我正在尝试使用乏味和乏味 ntlm 两者的配置如下 var tds require tedious ntlm var tds require tedious var config use
  • 为什么这些冲突出现在以下 XML 的 yacc 语法中

    我有以下 XML 语法 效果很好 program lt ID attribute list gt root root lt ID attribute list gt node list lt ID gt node list node s n
  • “作为自身执行”与跨数据库视图

    SQL Server 2016 数据库中有一个视图A从另一个数据库中的表中进行选择 B use A go create view TheView as select from B dbo SomeTable 我有 dbo 访问权限B数据库
  • 将 .MDF SQL Server 数据库与 ASP.NET 结合使用与使用 SQL Server

    我目前正在 ASP NET MVC 中编写一个网站 我的数据库 其中还没有任何数据 只有正确的表 使用 SQL Server 2008 我已将其安装在我的开发计算机上 我使用服务器资源管理器从应用程序连接到数据库 然后使用 LINQ to
  • 如何在实体框架中完全锁定一行

    我正在处理的情况是我们正在处理金钱交易 例如 我有一个用户钱包表 其余额位于该行 UserId Wallet Id Balance 现在 在我们的网站和网络服务中 每次发生特定交易时 我们都需要 检查是否有足够的资金可用于执行该交易 从余额
  • SQL 中基于下一条记录和上一条记录的复杂排序

    这是一个后续问题根据 SQL 中的下一条记录和上一条记录进行排序 https stackoverflow com questions 30477803 sorting based on next and previous records i
  • 如何访问 Scala XML 中的父元素

    The scala xml包表示带有标记树节点的 XML 但是这棵树在 Scala 2 7 中是单向的吗 因为似乎没有办法访问Elem给定的父级Elem 这似乎同样适用于父母Document 例如 在 XOM 中你有getParent an
  • 没有 Unicode 字节顺序标记。无法切换到 Unicode

    我正在使用 XSD 编写 XML 验证器 下面是我所做的 但是当验证器到达该线时while list Read 它给了我错误 没有 Unicode 字节顺序标记 无法切换到 Unicode 有人可以帮我解决吗 public class Va
  • Reporting Services 在哪里存储其日志文件

    最相关的谷歌结果似乎表明 为了访问日志 我们必须将您自己的日志表部署到数据库并制作报告服务写入它 http technet microsoft com en us library ms157403 aspx 简而言之 Reporting S
  • 数据库字段中的逗号分隔值

    我有一个产品表 该表中的每一行对应一个产品 并由唯一的 ID 标识 现在 每个产品都可以有多个与该产品关联的 代码 例如 Id Code 0001 IN ON ME OH 0002 ON VI AC ZO 0003 QA PS OO ME
  • 弹簧隔离支持吗? SQL快照隔离

    我们正在使用 SQL Server 快照隔离可能是提高性能和解决一些死锁问题的好方法 假设我们确实需要更改为快照隔离 我似乎找不到一种简单的方法来在 Springs 上启用快照隔离 Transactional 我发现以下 hibernate
  • SQL Server 连接其他表中不存在的位置

    Service Asset AssetService Id Name Id Name AssetId ServiceId
  • 删除数据库中的行后如何重新排序ID

    我正在使用 C 来制作具有 sql 数据库的程序 在数据库中我有一个名为Workers 它有一个自动增量和主键ID column 当我删除一条记录时 ID 之间会出现间隙 删除记录后如何重新排序 ID UPDATE 我要做的就是找到记录后将
  • CDATA 真的有必要吗?

    我经常使用内联 Javascript 通常是在我制作的 WordPress 主题中 我没有听说过将内联 Javascript 包装在 直到几个月前 几年来我一直在以相当的能力水平做这些事情 我用谷歌搜索了一下 听说人们使用它是因为他们的 J
  • 数字表与递归 CTE 生成一系列数字

    为什么使用数字表比使用递归 CTE 动态生成它们要快得多 在我的机器上 给定一张桌子numbers单列n 主键 包含从1到100000的数字 查询如下 select n from numbers 大约需要 400 毫秒才能完成 使用递归 C
  • SQL查询查找表的主键?

    我怎样才能找到哪一列首要的关键使用查询来创建表 这是重复的question https stackoverflow com questions 893874 mysql determine tables primary key dynami
  • 关键字“table”附近的语法不正确,无法提取结果集

    我使用 SQL Server 创建了一个项目 其中包含以下文件 UserDAO java public class UserDAO private static SessionFactory sessionFactory static se
  • 使用 powershell 将 XML 转换为特定的 JSON 结构

    需要有关将 xml 转换为特定 json 结构的帮助 XML 看起来像这样

随机推荐

  • 在R中逐行读取大文件而不带标题

    我在 R 中有一个非常大的数据文件 千兆 如果我尝试用 R 打开它 我会收到内存不足错误 我需要逐行读取文件并进行一些分析 我发现了一个关于这个问题的上一个问题 其中文件是由 n 行读取并跳转到带有 clump 的某些行 我已经使用了 Ni
  • Protractor:如何让配置文件更加灵活?

    我有一个想法让我的配置更加灵活 例如我有 10000 个具有相同参数的配置文件 seleniumAddress http localhost 4444 wd hub specs C Users Lilia Sapurina Desktop
  • 找不到经过训练的 NLU 模型(Actions on Google)

    我们正在使用 google SDK 上的 Actions 开发启动 我们迁移了我们的开发项目 UAT 突然它停止工作了 以前我们使用相同的方法并且每次都有效 机器人对初始短语响应一次 然后停止响应 它说抱歉 机器人名称 没有响应 请稍后再试
  • 如何在 Android 上打印堆栈跟踪(带有符号函数名称)?

    这个问题已经被问过很多次了 但从未得到真正的答案 今天我花了 5 到 6 个小时尝试将一些库移植到 Android libunwind liwdfl 这些库可能从未打算在 ARM 上运行 当然 无济于事 问题是Android缺少backtr
  • 当MySql数据库中添加新记录时,使用Jquery自动更新Div

    我正在为我的朋友制作一个社交网站 我想知道当数据库中添加新记录时 如何更新包含数据库中少量插入记录的 Div 简而言之 你一定见过 Facebook 的实时通知 当有人做某事时 这些通知就会淡出 这一切都发生在没有刷新整个实时通知 div
  • 以编程方式检查 SD 卡是否可用

    我的应用程序适用于仅具有 SD 卡的手机 因此 我想以编程方式检查 SD 卡是否可用以及如何找到 SD 卡可用空间 是否可以 如果是 我该怎么做 Boolean isSDPresent android os Environment getE
  • 在 Windows 中托管 Git 存储库

    目前是否有办法在 Windows 中托管共享 Git 存储库 据我所知 您可以使用以下命令在 Linux 中配置 Git 服务 git daemon 是否有本地 Windows 选项 缺少共享文件夹 来托管 Git 服务 编辑 我目前正在使
  • 创建两列无​​序列表

    我希望制作一个类似于下面的两列无序列表 但也想知道如何整合加号的图像 我正在寻找一种没有 CSS3 优点的解决方案 以便它可以支持较旧的浏览器 这是我的网站的链接 http jobspark ca job listings 由于我正在使用
  • magento 的 NGINX-FPM 配置设置

    我正在运行一个用 magento 开发的电子商务网站 我的服务器有 512mb RAM 和 2 6 core2duo 当我在网站上一次发送 50 个请求时 除了少数请求外 它不会响应 我也安装了清漆 我想知道我想要为我的网站进行的最佳设置
  • 变异,触发器/函数可能看不到它 - 触发器执行期间出错

    CREATE OR REPLACE TRIGGER UPDATE TEST 280510 AFTER insert on TEST TRNCOMPVISIT declare V TRNCOMPNO NUMBER 10 CURSOR C1 I
  • 使用 Findbugs 编写一个检测器来搜索“System.out.println”的使用

    我正在尝试编写一个错误检测器来使用 Findbugs 查找方法调用 System out println 的实例 我知道字节码中的 System out println 被编译为对 GETSTATIC 的调用 将 System out 推入
  • android - 活动切换时意外的短暂方向变化

    我想在我的 Android 应用程序中动态设置屏幕方向 为此我使用 activity setRequestedOrientation ActivityInfo SCREEN ORIENTATION PORTRAIT 和类似的 到目前为止 效
  • 定义 Vue-Router 路由时访问 Vuex 状态

    我有以下 Vuex 商店 main js import Vue from vue import Vuex from vuex Vue use Vuex init store const store new Vuex Store state
  • Jetty 和最大内容大小

    我使用 Jetty 9 4 8 我想限制可以发布到服务器的数据量 为此 我添加到 jetty xml
  • CUDA 应用程序在几秒钟后超时并失败 - 如何解决此问题?

    我注意到 CUDA 应用程序在失败并退出之前的最大运行时间往往为 5 15 秒 我意识到最好不要让 CUDA 应用程序运行那么长时间 但假设使用 CUDA 是正确的选择 并且由于每个线程的顺序工作量必须运行那么长时间 有什么方法可以延长这个
  • VBA复制列的宽度

    下面的 VBA 代码从源数据表复制数据并将其粘贴到特定表上 但是 我还需要它来将列的宽度粘贴到源数据表上 这可能吗 谢谢你的帮助 Private Sub Worksheet Change ByVal Target As Range Dim
  • 创建进程以在新的 Windows 桌面上运行 IE

    我正在尝试设置一个 IE kiosk 在单独的桌面上运行 IE 当我测试时 我只是正常启动 IE 不是在 kiosk 模式下 但是尽管 IE 在新桌面上启动 但它不会加载命令字符串中指定的初始页面 它只是坐在那里 沙漏闪烁打开和关闭非常快
  • 无法编译 C# 默认接口方法

    C 8 0 有一个新功能 可以让您向接口上的方法添加默认实现 要么我做错了什么 要么这个功能没有像宣传的那样工作 我猜是前者 我使用以下代码创建了一个新的 NET Core 3 1 控制台应用程序 using System namespac
  • JQuery .append 标记被忽略[重复]

    这个问题在这里已经有答案了 我有以下 HTML div div
  • 使用外键作为第一个表的标识列批量插入嵌套 xml

    我有一个 xml 如下