開篇介紹
在 SSIS 中並沒有直接提供從數據源到 XML 的轉換輸出,Destination 的輸出對象有 Excel File, Flat File, Database 等,但是並沒有直接提供 XML 文件輸出的配置。
但是我們仍然可以通過下面這些方法來實現:
方法一:在數據流中使用平面文件對字符串 XML 轉換輸出
方法二:在控制流中使用 Script Task 輸出 XML 文件
需求描述
要將下面的這種查詢結果轉換成 XML -
需要輸出成 XML 文件的格式 -
那么首先在SQL 語句中就需要將格式轉換一下,可以將將查詢結果包裝成相應的 XML 格式 -
SELECT * FROM T009_SALES_ORDER_DETAIL FOR XML RAW('SalesOrderDetail'),ROOT('SalesOrder'),ELEMENTS
關於 SQL XML 查詢的內容,不是文本的重點,大家可以參考博客園中其他博友的博客:
在數據流中使用平面文件對字符串 XML 轉換輸出
在 Data Flow 中新建一個 Source 並且使用上面的 SQL 語句,這個 SQL 語句查詢的結果是一個 XML 格式的大字符串。
它的 Columns 輸出的就是包含了整個 XML 結果的字符串。
為了兼容后面文件輸出時的字符類型轉換問題,添加一個 Data Convertion 將這個輸出改變一下數據類型,這里選擇的是 Unicode text stream [DT_NTEXT]。
新建一個 Flat File Connection Manager,文件后綴名稱是 .xml 結尾。如果測試環境是中文,或者輸出的字符串中有雙字節字符類型,那么就應該在 Locale 選擇適當的環境語言,並且應該勾選上 Unicode。
並且在 Advanced 中新增加一個 Column,並且一定要注意在類型中應該選擇的應該是 Unicode text stream。並且這也就是要用 Flat File Connection 而不使用 Raw File 的原因,因為 Raw File 中不支持 Text 文本數據類型。
新建一個 Flat File Destination 組件,並且使用上面編輯好了的 Flat File Connection Manager。
使用剛才在 Data Conversion 中編輯過的新 Column 與輸出 Column 匹配。
保存並執行 SSIS Package。
你認為一定成功了,對吧!打開一看,傻眼了吧!
原因是什么呢?我們可以回到 OLE_SRC_OrderDetail 中 Preview 一下,看到了嗎?在這里這個輸出是Byte字節數組。
需要將上面的 SQL 再次包裝成 XML 一下,將這個查詢結果單獨包裝成一個字符串格式。
SELECT ( SELECT TOP 10 [SalesOrderID] ,[SalesOrderDetailID] ,[CarrierTrackingNumber] ,[OrderQty] ,[ProductID] ,[UnitPrice] ,[UnitPriceDiscount] ,[ModifiedDate] FROM [Sales].[SalesOrderDetail] FOR XML RAW('SalesOrderDetail'),ROOT('SalesOrder'),ELEMENTS )AS XML_Order
不包裝時在 SQL Server 中的查詢結果可以理解它是一個正兒八經的 XML 文件,點擊打開就是一整個 XML 格式的文本 -
包裝之后在 SQL Server 中的查詢結果 - 這才是真正的文本數據。
再次 Preview 一下,看到 XML 格式的字符串。
修改后面的 Mapping 關系,並保存執行輸出,在瀏覽器中查看 XML 文件結果。
在控制流中使用 Script Task 輸出 XML 文件
新建兩個變量,一個保存文件路徑,另一個保存 XML 字符串。
注意這時使用的是 Execute SQL Task 是一個控制流控件, SQL Statement 中使用上面那個包裝過的 XML 查詢。
Result Set 中將輸出的 XML 結果用上面新建的變量來保存。
新建一個 Script Task 傳入兩個變量。
Script 中引用 System.IO 命名空間,然后就是下面這幾句代碼。
public void Main() { string content = Dts.Variables["User::XmlString"].Value.ToString(); string filePath = Dts.Variables["User::XmlFilePath"].Value.ToString(); StreamWriter writer = new StreamWriter(filePath); writer.WriteLine(content); writer.Close(); Dts.TaskResult = (int)ScriptResults.Success; }
保存執行並查看輸出的 XML 文件。
輸出的結果有一個 ROOT ,這可以在代碼中非常容易的處理掉。
string content = Dts.Variables["User::XML_STRING"].Value.ToString().Replace("<ROOT>", "").Replace("</ROOT>", "");
PS : 更新補充一下不使用 SSIS 工具直接通過 SQL 輸出到文件的方式 - XP_CMDSHELL
EXEC sp_configure 'show advanced options', 1 GO RECONFIGURE GO EXEC sp_configure 'xp_cmdshell', 1 GO RECONFIGURE GO EXEC XP_CMDSHELL 'BCP "SELECT(SELECT TOP 2 * FROM [AdventureWorks2012].[Sales].[SalesOrderDetail] FOR XML RAW(''SalesOrderDetail''),ROOT(''SalesOrder''),ELEMENTS )AS XML_Order " QUERYOUT "D:\text.xml" -c -T' EXEC sp_configure 'show advanced options', 1 GO RECONFIGURE GO EXEC sp_configure 'xp_cmdshell', 0 GO RECONFIGURE GO
這樣也是可以的,但是一般情況下至少我很少選擇這種方式,原因主要有幾個:
1. XP_CMDSHELL 默認被禁用的,要使用 sp_configure 來控制,因此需要級別比較高的權限,但是在實際操作中客戶在很多時候不會給那么多的權限。
2. 很重要的一點就是在 BI 當中,我們所有的文件輸出一定有日志的記錄,包括輸出路徑,起始時間,文件大小等等,使用 SSIS 可以更好的跟 Process Log 結合起來使用。
3. 如果是一些比較復雜的 SQL 查詢輸出,在 SQL 中拼接字符串也是一件非常痛苦的事情。
更多 BI 文章請參看 BI 系列隨筆列表 (SSIS, SSRS, SSAS, MDX, SQL Server) 如果覺得這篇文章看了對您有幫助,請幫助推薦,以方便他人在 BIWORK 博客推薦欄中快速看到這些文章。