[英]SSIS/SQL Server XML
我正在從SQL Server 2008R2創建XML輸出。 下面是我想要的xml的結構。 (我會盡可能地清楚,但是如果你需要更多的信息,請告訴我)問題我正在使用節點“RecordId”。 該字段必須是整個XML中的運行序列,而不管它在哪個節點下。 即,任何類別下的節點“RecordId”的每次出現將比前一個節點的值大1,即使它在不同的類別下。
我的主要約束是,我將只能嚴格使用T-SQL,SSIS(可以使用VB或C#進行腳本任務)。
<Root>
<includedFileHeader>
<GenDatetime>2017-01-13T11:53:36</GenDatetime>
<OFtype>PD</OFtype>
<issuerID>ABCDE</issuerID>
**<RecordId>1</RecordId>**
</includedFileHeader>
<includedIssuerResult>
<issuerId>ABCDE</issuerId>
**<RecordId>2</RecordId>**
<includedPlanResult>
<planId>2</planId>
<insPlanId>123456789</insPlanId>
**<RecordId>4</RecordId>**
<ClassStatusType>
<Code>A</Code>
</ClassStatusType>
<includedDetails>
<DetailId>48</DetailId>
<DetailClmId>A3456H567</DetailClmId>
**<RecordId>4</RecordId>**
</includedDetails>
<includedDetails>
<DetailId>74</DetailId>
<DetailClmId>163364170257204</DetailClmId>
**<RecordId>5</RecordId>**
</includedDetails>
</includedPlanResult>
<includedPlanResult>
<planId>3</planId>
<insPlanId>343546337</insPlanId>
**<RecordId>6</RecordId>**
<ClassStatusType>
<Code>A</Code>
</ClassStatusType>
<includedDetails>
<DetailId>55</DetailId>
<DetailClmId>A78947J780</DetailClmId>
**<RecordId>7</RecordId>**
</includedDetails>
<includedDetails>
<DetailId>44</DetailId>
<DetailClmId>146545165A54</DetailClmId>
**<RecordId>8</RecordId>**
</includedDetails>
</includedIssuerResult>
</Root>
我甚至無法在T-sql中實現,但是嘗試在腳本任務中使用一些VB / C#代碼,使用XMLReader,Streamreader / writer,沒有任何效果。 非常感謝任何幫助。
一般來說,我會避免在字符串級別處理XML。 在這種情況下,這可能是一種解決方法......
DECLARE @xml XML=
N'<Root>
<includedFileHeader>
<GenDatetime>2017-01-13T11:53:36</GenDatetime>
<OFtype>PD</OFtype>
<issuerID>ABCDE</issuerID>
<RecordId>99</RecordId>
</includedFileHeader>
<includedIssuerResult>
<issuerId>ABCDE</issuerId>
<RecordId>33</RecordId>
<includedPlanResult>
<planId>2</planId>
<insPlanId>123456789</insPlanId>
<RecordId>22</RecordId>
<ClassStatusType>
<Code>A</Code>
</ClassStatusType>
<includedDetails>
<DetailId>48</DetailId>
<DetailClmId>A3456H567</DetailClmId>
<RecordId>66</RecordId>
</includedDetails>
<includedDetails>
<DetailId>74</DetailId>
<DetailClmId>163364170257204</DetailClmId>
<RecordId>11</RecordId>
</includedDetails>
</includedPlanResult>
<includedPlanResult>
<planId>3</planId>
<insPlanId>343546337</insPlanId>
<RecordId>6</RecordId>
<ClassStatusType>
<Code>A</Code>
</ClassStatusType>
<includedDetails>
<DetailId>55</DetailId>
<DetailClmId>A78947J780</DetailClmId>
<RecordId>7</RecordId>
</includedDetails>
<includedDetails>
<DetailId>44</DetailId>
<DetailClmId>146545165A54</DetailClmId>
<RecordId>8</RecordId>
</includedDetails>
</includedPlanResult>
</includedIssuerResult>
</Root>';
- 查詢
WITH Splitted AS
(
SELECT CAST('<x>' + REPLACE((SELECT CAST(@xml AS NVARCHAR(MAX)) FOR XML PATH('')),'<RecordId>','</x><x>') + '</x>' AS XML) AS Part
)
,Parted AS
(
SELECT p.value(N'(./text())[1]',N'nvarchar(max)') AS line
,ROW_NUMBER() OVER(ORDER BY (SELECT NULL))-1 AS nr
FROM Splitted
CROSS APPLY Part.nodes(N'/x') AS A(p)
)
SELECT CAST(
(SELECT line FROM Parted WHERE nr=0)
+ (
SELECT '<RecordId>' + CAST(nr AS NVARCHAR(10)) + '</RecordId>' + SUBSTRING(line,CHARINDEX('<',line,5),10000)
FROM Parted
WHERE nr>0
ORDER BY nr
FOR XML PATH(''),TYPE
).value('(./text())[1]',N'nvarchar(max)') AS XML);
第一個CTE Splitted
使用基於XML 的即時字符串拆分方法。 這里的問題是,像<
或>
這樣的字符會讓這個中斷。 這就是我在實際拆分之前使用SELECT ... FOR XML PATH('')
的原因。 這將隱式地逃避所有禁用的字符。 下一步是將字符串拆分為<RecordId>
,現在是<RecordId>
第二個CTE Parted
使用.nodes()
獲取列表派生表,使用ROW_NUMBER
獲取運行編號。
最后的SELECT
重新連接在正確位置插入編號<RecordId>
的分開的行。
感謝大家的建議和幫助。 我設法提出了一個解決方案(類似於Laughing Vergil的想法)(雖然不是那么整潔,但能夠在同一時間得到我想要的並不是很慢)。
這就是我所做的:我創建了一個標量UDF,它將需要2個輸入1.XML數據,2.我想要序列的標簽名稱(在這種情況下它是“RecordID”,只是重用相同的if)未來需要不同的標簽)。 此外,當我生成XML時,我將“ <RecordID/>
”字段默認為0,這將在其中進行搜索和替換。
該函數的作用:1。將輸入XML轉換為VARCHAR(MAX)2。找到第一個出現的“ <RecordID/>
”並將#1作為序列3填充。繼續循環遍歷XML,直到找到最后一個匹配和每次出現用適當的循環數(@i)填充它
CREATE FUNCTION dbo.UDF_UPDATE_RECORDID_XML (
--XML Data
@xmld VARCHAR(MAX),
--Tag/Node name for the RecordID
--ex: if <RecordID>0</RecordID>, then pass 'RecordID'
@rec_tag VARCHAR(100)
)
RETURNS XML
AS
BEGIN
--o/p param
DECLARE @op_xmld VARCHAR(MAX)
--processing params
DECLARE @i INT
DECLARE @j INT
DECLARE @prev_i INT
--search pattern
DECLARE @pat VARCHAR(100) = '<' + @rec_tag + '>0</' + @rec_tag + '>'
SELECT @op_xmld = @xmld
--Find first occurance of the pattern in the XML
SELECT @i = PATINDEX('%' + @pat + '%', @op_xmld)
, @j = 1
SELECT @prev_i = @i
--Loop until there is no match for the pattern
WHILE (@i > 0)
BEGIN
--Replace the identified substring with the sequence number in between
SET @op_xmld = STUFF(@op_xmld, @i, LEN(@pat), '<' + @rec_tag + '>' + CAST(@j AS VARCHAR(20)) + '</' + @rec_tag + '>')
--sequence number
SET @j = @j + 1
--store the current index value of the pattern
--so the next search can happen after this point
SET @prev_i = @i
--Search down for the pattern from the previous index value
SELECT @i = CHARINDEX(@pat, @op_xmld, @prev_i + LEN(@pat))
END
RETURN CAST(@op_xmld AS XML)
END
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.