2016-05-04 48 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格式。我編寫了示例代碼,不考慮日期格式。不過謝謝你的迴應,我知道日期格式很重要,但不是你給我的所有細節! –