SQL数据作为XML元素

时间:2015-06-19 18:54:29

标签: sql-server xml

我在使用SQL生成XML方面有点新鲜。我试图从这个查询生成XML:

SELECT RptType, DataType, Branch, ACC, Actual 
FROM ReportingTb

查询产生以下结果:

RptType   DataType   Branch    Acc    Actual
-------   --------   -------   ----   -----------
MTD       UPS        Arizona   Total  2279.00000
MTD       UPS        Arizona   Oral   543.00000
MTD       UPS        Arizona   Tube   532.00000
MTD       UPS        Arizona   Other  1.00000

我想在前4列中使用查询结果作为XML元素,如下所示:

<MTD>
  <UPS>
    <Arizona>
      <Total>
        <Actual>2279.00000</Actual>
      </Total>
      <Oral>
        <Actual>543.00000</Actual>
      </Oral>
      <Tube>
        <Actual>532.00000</Actual>
      </Tube>
      <Other>
        <Actual>1.00000</Actual>
      </Other>
    </Arizona>
  <UPS>
</MTD>

有人能指出我正确的方向如何做到这一点?我是否可以使用T-SQL并循环查询结果以生成XML文件?

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

这在技术上是可行的,但由于一些原因它真的很糟糕。相反,你应该重新考虑你的XML结构,更像是这样的东西:

<Root>
  <ReportingTb RptType="MTD" DataType="UPS" Branch="Arizona">
    <Actual Acc="Total">2279.00000</Actual>
    <Actual Acc="Oral">543.00000</Actual>
    <Actual Acc="Tube">532.00000</Actual>
    <Actual Acc="Other">1.00000</Actual>
  </ReportingTb>
</Root>

使用此查询:

DECLARE @t TABLE (RptType varchar(20),   DataType VARCHAR(20),   Branch VARCHAR(20),    Acc VARCHAR(20),   Actual numeric(10,5));
INSERT @t VALUES
('MTD',  'UPS'        ,'Arizona',   'Total',  2279.00000)
,('MTD',  'UPS'        ,'Arizona',   'Oral',  543.00000)
,('MTD',  'UPS'        ,'Arizona',   'Tube',  532.00000)
,('MTD',  'UPS'        ,'Arizona',   'Other',  1.00000);

SELECT RptType as '@RptType'
    ,DataType as '@DataType'
    ,Branch as '@Branch'
    ,(SELECT 
         Acc AS '@Acc'
        ,Actual as '*'
    FROM @t t2
    WHERE t2.RptType = t1.RptType AND t2.DataType = t1.DataType AND t2.Branch = t1.Branch
    FOR XML PATH('Actual'), TYPE)
FROM @t t1
GROUP BY RptType, DataType, Branch
FOR XML PATH('ReportingTb'), ROOT('Root');

这为您提供了可以针对模式进行合理验证的XML(而不是必须包含许多可能的节点名称的模式)。它将更自然地处理不同的分组可能性,它将处理FOR XML在幕后处理的所有XML怪异。

那就是说,技术上可以实现你原来的愿望;这是一个可以执行此操作的查询:

SELECT 
    CAST('<' + RptType + '>'
    + (SELECT 
        '<' + DataType + '>' 
        + (SELECT
            '<' + Branch + '>'
            + REPLACE(REPLACE(
            (SELECT
                 '#' + acc + '!' as '*' , Actual, '#/' + acc + '!' as '*'
                FROM @t t4 WHERE t4.Branch = t3.Branch AND t4.DataType = t2.DataType AND t4.RptType = t1.RptType
                FOR XML PATH('')), '#', '<'), '!', '>')

            + '</' + Branch + '>'
            FROM  @t t3  WHERE t3.DataType = t2.DataType AND t3.RptType = t1.RptType GROUP BY Branch)
        + '</' + DataType + '>'
        FROM @t t2  WHERE t2.RptType = t1.RptType GROUP BY DataType)
    + '</' + RptType + '>'  AS XML)
FROM @t t1
GROUP BY RptType

请注意,你不应该这样做,这真的是丑陋的hackery (我只是告诉你如何在那里找到一部分的方式让你知道有多丑)。它真的变得更糟。我正在使用奇怪的字符串替换,可能会或可能不会在野外工作。最重要的是,如果任何节点有一个无效的XML字符,你必须逃避它 - 可能会抛出一些额外的替换(REPLACE(col, '<', '&lt;'))或其他东西,但这又是丑陋的,必须全部重复几个值。您基本上使用SQL Server作为XML编写器,它实际上并不意味着这样做。如果绝对必须具有此结构,那么您应该将数据传递给CLR类,该类可以正确使用XmlWriterXDocument之类的内容来使用这些值编写实际的XML 。您甚至可以将CLR类放在SQL Server中并从存储过程中调用它。