结果集中的 XML 输出 (T-SQL)

Posted

技术标签:

【中文标题】结果集中的 XML 输出 (T-SQL)【英文标题】:Output of XML in Resultset (T-SQL) 【发布时间】:2022-01-17 13:19:30 【问题描述】:

我有一个 XML 文件,我想创建一个带有特定输出的 SELECT 语句。

<Errors>
  <Error CheckNumber="5" Message="Within the unit there are identifier duplicates.">
    <ProductionInfo ProductionOrderNo="ABC12345" >
      <Identifier>
        <RawID>67484295</RawID>
        <UnitCode>.gEft?s</UnitCode>
        <UnitGTIN>1234567890</UnitGTIN>
      </Identifier>
      <Identifier>
        <RawID>67484297</RawID>
        <UnitCode>_Yo*IpH</UnitCode>
        <UnitGTIN>1234567890</UnitGTIN>
      </Identifier>
      <Identifier>
        <RawID>67484301</RawID>
        <UnitCode>3IBIsik</UnitCode>
        <UnitGTIN>1234567890</UnitGTIN>
      </Identifier>
      <Identifier>
        <RawID>67484318</RawID>
        <UnitCode>g&lt;*fnh6</UnitCode>
        <UnitGTIN>1234567890</UnitGTIN>
      </Identifier>
      <Identifier>
        <RawID>67484326</RawID>
        <UnitCode>LI?jTW/</UnitCode>
        <UnitGTIN>1234567890</UnitGTIN>
      </Identifier>
    </ProductionInfo>
  </Error>
  <Error CheckNumber="6" Message="The unit does not contain the required number of content information.">
    <ProductionInfo ProductionOrderNo="ABC12345" ProductionLine_InternalNo="11204">
      <Identifier>
        <RawID>67484295</RawID>
        <UnitCode>.gEft?s</UnitCode>
        <UnitGTIN>1234567890</UnitGTIN>
      </Identifier>
      <Identifier>
        <RawID>67484297</RawID>
        <UnitCode>_Yo*IpH</UnitCode>
        <UnitGTIN>1234567890</UnitGTIN>
      </Identifier>
  </ProductionInfo>
  </Error>
</Errors>

我想要的是两列(ErrorMessage & Identifier)的输出。 Identifier-Column 应该是底层标识符的字符分隔列表。

所以我的例子中的输出应该(在我的例子中,分隔符是'@')有两行,如:

Example image of output.

最终的 SELECT 会是什么样子才能得到这个输出?

非常感谢!

【问题讨论】:

根据问题指南,请展示您的尝试并告诉我们您发现了什么(在本网站或其他地方)以及为什么它不能满足您的需求。 【参考方案1】:

您可以使用query 选择节点属性和元素。

DECLARE @temp TABLE (ErrorsValues XML)
INSERT INTO @temp
SELECT '
<Errors>
  <Error CheckNumber="5" Message="Within the unit there are identifier duplicates.">
    <ProductionInfo ProductionOrderNo="ABC12345" >
      <Identifier>
        <RawID>67484295</RawID>
        <UnitCode>.gEft?s</UnitCode>
        <UnitGTIN>1234567890</UnitGTIN>
      </Identifier>
      <Identifier>
        <RawID>67484297</RawID>
        <UnitCode>_Yo*IpH</UnitCode>
        <UnitGTIN>1234567890</UnitGTIN>
      </Identifier>
      <Identifier>
        <RawID>67484301</RawID>
        <UnitCode>3IBIsik</UnitCode>
        <UnitGTIN>1234567890</UnitGTIN>
      </Identifier>
      <Identifier>
        <RawID>67484318</RawID>
        <UnitCode>g&lt;*fnh6</UnitCode>
        <UnitGTIN>1234567890</UnitGTIN>
      </Identifier>
      <Identifier>
        <RawID>67484326</RawID>
        <UnitCode>LI?jTW/</UnitCode>
        <UnitGTIN>1234567890</UnitGTIN>
      </Identifier>
    </ProductionInfo>
  </Error>
  <Error CheckNumber="6" Message="The unit does not contain the required number of content information.">
    <ProductionInfo ProductionOrderNo="ABC12345" ProductionLine_InternalNo="11204">
      <Identifier>
        <RawID>67484295</RawID>
        <UnitCode>.gEft?s</UnitCode>
        <UnitGTIN>1234567890</UnitGTIN>
      </Identifier>
      <Identifier>
        <RawID>67484297</RawID>
        <UnitCode>_Yo*IpH</UnitCode>
        <UnitGTIN>1234567890</UnitGTIN>
      </Identifier>
  </ProductionInfo>
    </Error>
</Errors>'

--查询

select y.value('@Message','varchar(300)') as ErrorMessage
      ,y.query('data(ProductionInfo/Identifier/UnitCode)')
        .value('.','nvarchar(max)') as Identifier 
from @temp  t
cross apply ErrorsValues.nodes('Errors/Error') x(y);

输出:

【讨论】:

@nicetomitja 这个答案指出了正确的方向,但有一些缺陷:使用y.value('@Message','varchar(300)') as ErrorMessage 以获得正确的结果。将.query()CAST() 一起使用不会重新转义实体(例如&amp;amp; =&gt; "&amp;")。此外,出于同样的原因,请使用y.query('data(ProductionInfo/Identifier/UnitCode)').value('.','nvarchar(max)') as Identifier。最后但同样重要的是:XQuery 的data() 将始终使用空白作为分隔符。如果您的标识符可能包含空格,这可能无法正常工作... @Shnugo 最后一个问题的解决方案是使用/text() 而不是data(),如已编辑 @Charlieface,不,您的编辑违反了要求(标识符列应该是底层标识符的字符分隔列表)使用您的方法将直接粘合所有部分,而data() 返回它们之间有一个空格。很小,但很重要。如果内容可以包含空白,则可以使用 FLWOR-query 和 XQuery 的 concat() 并在末尾添加 STUFF()。但是 - 正如 OP 所接受的那样 - 空白似乎没问题。

以上是关于结果集中的 XML 输出 (T-SQL)的主要内容,如果未能解决你的问题,请参考以下文章

SqlServerSqlServer编程语言T-SQL的游标使用

T-SQL 将动态SQL的结果集赋值到变量

T-sql for xml path使用(转)

如何在单个结果集中列出 SQL Server 中所有数据库中的所有表?

合并查询结果集UNION(去重), UNION ALL(不去重),INTERSECT(交集),MINUS(差集,第一个结果集减去第二个结果集,第一个结果集中不在第二个结果集中的记录行)

T-SQL基础之集合运算