Sql server 将1-to-n XML列转换为表格数据
我在MS SQL server上有一个表,它以XML格式保存有关报表的信息。该表由两个字段组成:第一个字段包含业务键,第二个字段包含XML格式的整个报表 这些报告每个都包括几张图片。XML保存有关这些图片的信息,例如它们的文件名、拍摄日期等。我想将这些信息提取到一个表中,其中每个记录只保存一张照片的信息。我已经找到了实现这一点的方法,但我一直遇到的问题是,我需要在这个表中为源表中的每条记录创建多条记录。我怎样才能做到这一点 业务密钥也需要在最终的表中。这个业务密钥可以在XML数据中找到,但在源表中还有一个单独的字段,如前面所述,可以在其中找到它。XML列的内容可能类似于以下内容:Sql server 将1-to-n XML列转换为表格数据,sql-server,xml,Sql Server,Xml,我在MS SQL server上有一个表,它以XML格式保存有关报表的信息。该表由两个字段组成:第一个字段包含业务键,第二个字段包含XML格式的整个报表 这些报告每个都包括几张图片。XML保存有关这些图片的信息,例如它们的文件名、拍摄日期等。我想将这些信息提取到一个表中,其中每个记录只保存一张照片的信息。我已经找到了实现这一点的方法,但我一直遇到的问题是,我需要在这个表中为源表中的每条记录创建多条记录。我怎样才能做到这一点 业务密钥也需要在最终的表中。这个业务密钥可以在XML数据中找到,但在源表
<Report>
<ReportKey>0000001</ReportKey>
[...]
<Photos>
<Photo>
<Filename>1.jpg</Filename>
<Date>01-01-2015</Date>
</Photo>
<Photo>
<Filename>2.jpg</Filename>
<Date>01-01-2016</Date>
</Photo>
[...]
</Photos>
[...]
</Report>
也许我误解了这个问题。但是,试试这个
create table t (
[Key] int,
[Filename] nvarchar(max),
[Date] date
)
这不是一个答案,但足够重要,不会以评论结束:
对日期格式要非常小心。我不知道XML是如何生成的,但XML中的日期应该是ISO 8601 yyyy mm dd或yyyy mm ddThh:mm:ss
您的格式取决于文化
试试这个:
set language french;
declare @xml as xml ='<x><Date>08-03-2015</Date></x>';
select @xml.value('(/x/Date)[1]','datetime');
set language english;
select @xml.value('(/x/Date)[1]','datetime');
你看,结果不同吗
现在试着把日期定在3月13日。甚至还有一个转换异常 根据评论,OP需要一种从表行数据中获取此信息的方法,而现有的答案还不够解决方案 你可以试试这个:
CREATE TABLE #YourTable(BusinessKey VARCHAR(10),ReportData XML);
INSERT INTO #YourTable VALUES
('0000001','<Report>
<ReportKey>0000001</ReportKey>
<Photos>
<Photo>
<Filename>1.jpg</Filename>
<Date>2015-01-01</Date>
</Photo>
<Photo>
<Filename>2.jpg</Filename>
<Date>2016-05-13</Date>
</Photo>
</Photos>
</Report>')
,('0000002','<Report>
<ReportKey>0000002</ReportKey>
<Photos>
<Photo>
<Filename>3.jpg</Filename>
<Date>2015-04-19</Date>
</Photo>
<Photo>
<Filename>4.jpg</Filename>
<Date>2016-12-10</Date>
</Photo>
</Photos>
</Report>');
SELECT BusinessKey AS Table_Key
,ReportData.value('(/Report/ReportKey)[1]','varchar(10)') AS XML_Key
,Photo.value('Filename[1]','varchar(max)') AS Photo_Filename
,Photo.value('Date[1]','date') AS Photo_Date
FROM #YourTable
CROSS APPLY ReportData.nodes('/Report/Photos/Photo') AS A(Photo);
GO
DROP TABLE #YourTable;
回答得很好,我这边+1。一些小提示:您不需要。/,只需要.value'ReportKey[1],'int'就足够了,而且——如果我理解正确的话——有一个包含许多记录的表,不需要将结果存储在持久表中。也许你想在你的答案中反映这一点……谢谢你的回答,但我已经尝试过这种类型的解决方案,事后看来,我应该说明这一点。问题在于,我希望代码在整个源表上运行,并且对于源表中的每个记录,在查询结果中创建几个记录。您在这里编写的代码将只在一个XML文件上运行,而不是在多个XML文件上运行。我考虑过的一些解决方案是连接所有xml文件,尽管这将意味着巨大的性能损失,或者从查询结果中设置@xml变量。不过,我不太确定如何做到这一点。我已经检查了XML文件,它们是您提到的ISO格式。我编写的示例代码不考虑日期格式。尽管如此,感谢您的回复,我知道日期格式很重要,但并不是您给我的所有细节!多亏了你的最后一个解决方案,我今天才得以工作。我一定要投赞成票,把问题标为已解决。谢谢你的帮助,你太棒了!
set language french;
declare @xml as xml ='<x><Date>08-03-2015</Date></x>';
select @xml.value('(/x/Date)[1]','datetime');
set language english;
select @xml.value('(/x/Date)[1]','datetime');
CREATE TABLE #YourTable(BusinessKey VARCHAR(10),ReportData XML);
INSERT INTO #YourTable VALUES
('0000001','<Report>
<ReportKey>0000001</ReportKey>
<Photos>
<Photo>
<Filename>1.jpg</Filename>
<Date>2015-01-01</Date>
</Photo>
<Photo>
<Filename>2.jpg</Filename>
<Date>2016-05-13</Date>
</Photo>
</Photos>
</Report>')
,('0000002','<Report>
<ReportKey>0000002</ReportKey>
<Photos>
<Photo>
<Filename>3.jpg</Filename>
<Date>2015-04-19</Date>
</Photo>
<Photo>
<Filename>4.jpg</Filename>
<Date>2016-12-10</Date>
</Photo>
</Photos>
</Report>');
SELECT BusinessKey AS Table_Key
,ReportData.value('(/Report/ReportKey)[1]','varchar(10)') AS XML_Key
,Photo.value('Filename[1]','varchar(max)') AS Photo_Filename
,Photo.value('Date[1]','date') AS Photo_Date
FROM #YourTable
CROSS APPLY ReportData.nodes('/Report/Photos/Photo') AS A(Photo);
GO
DROP TABLE #YourTable;