【发布时间】:2014-09-30 15:36:31
【问题描述】:
我有一个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 Database 上运行,有以下 2 个表来存储这些记录:
Record(RecordId [PK、身份、自动增量]、名称、工作室)Artist(RecordId [外键指 Record.RecordId]、ArtistName、Age)
是否可以使用 xml 节点方法在一次遍历 xml 中将记录批量插入到 Record 表中,获取 RecordIds,然后将艺术家信息批量插入到 Artist 表中?
我一直在寻找一种有效的方法来做到这一点,但徒劳无功。
我尝试了类似于here 和here 描述的方法,但我无法找到解决方案。
任何指向解决方案的指针都会有很大帮助。
更新: @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:非常感谢您为我指明了正确的方向。欢迎提出任何改进此解决方案的建议。
【问题讨论】:
-
为什么单次遍历需要它?另外,请向我们展示您已经拥有的东西。
-
中的 元素是否唯一? -
@srutzky:是的,名字是独一无二的。
-
@RBarryYoung:我只需要以一种有效的方式来做,而不一定是一次遍历。我尝试了我之前共享的 2 个链接中描述的内容,但只能获得解决方案的一半。结果与预期的结果相去甚远,因此没有分享任何其他内容。
-
@nikhil :抱歉,我没有看到您的 cmets 和更新。使用带有名称的“@”在问题或答案的正文中不起作用。你需要评论我的回答。为什么需要使用节点?这很好,但效率可能会降低。但我会考虑到这一点来更新我的答案。请使用那里的 cmets 进行交流:)。
标签: sql-server xml tsql azure-sql-database sqlxml