2016-05-04 23 views
2

我在MS SQL服务器上有一个表格,其中包含有关XML格式报表的信息。该表由两个字段组成:第一个包含业务密钥,第二个包含XML格式的整个报告。将1对n的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> 

我想最后的表看起来像这样:

+---------+----------+------------+ 
| Key | Filename | Date | 
+---------+----------+------------+ 
| 0000001 | 1.jpg | 01-01-2015 | 
| 0000001 | 2.jpg | 01-01-2016 | 
+---------+----------+------------+ 
+0

我已经能够让今天的工作,多亏了你最后的解决方案。我会确保将其解决并将问题标记为已解决。感谢您的帮助,您一直很棒! –

回答

1

根据意见,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

也许我误解了这个问题。但是,试试这个。

create table t (
    [Key]  int, 
    [Filename] nvarchar(max), 
    [Date]  date 
) 


declare @xml as 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>' 

insert into t ([Key], [Filename], [Date]) 
select n.value('ReportKey[1]', 'int') 
    , x.value('Filename[1]', 'nvarchar(max)') 
    , x.value('Date[1]',  'date') 
from @xml.nodes('Report') as r(n) 
cross apply r.n.nodes('Photos/Photo') as t(x) 

select * from t 
+1

很棒的回答,+1在我身边。一些小提示:你不需要'。/',只需'.value('ReportKey [1]','int')'就足够了,并且 - 如果我正确理解这个 - 有一个包含许多记录的表并且不需要将结果存储在持久表中。也许你想在你的回答中反映这一点...... – Shnugo

+0

感谢您的回答,但我已经尝试过这种类型的解决方案(我应该事后说明)。问题在于,我希望代码运行在整个源表上,并且对于该源表中的每个记录,都会在查询结果中创建多个记录。你在这里编写的代码只能运行在一个XML文件上,而不是几个。我考虑过的一些解决方案是连接所有xml文件(尽管这意味着巨大的性能损失),或者从查询结果中设置@xml变量。不过,我不太确定该怎么做。 –

2

这是不是一个答案,但足够重要的不就结了一个评论:

要非常小心的日期格式。我不知道您的XML是如何生成的,但内的 XML应该是ISO 8601(yyyy-mm-ddyyyy-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日。甚至有一个转换异常!

+0

我已经检查过XML文件,并且它们采用了你提到的ISO格式。我编写了示例代码,不考虑日期格式。不过谢谢你的回应,我知道日期格式很重要,但不是你给我的所有细节! –