簡體   English   中英

SSIS / SQL Server XML

[英]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('')),'&lt;RecordId&gt;','</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> ,現在是&lt;RecordId&gt;

第二個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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM