【问题标题】:Concatenation of strings by for xml path通过 for xml 路径连接字符串
【发布时间】:2012-12-14 12:10:09
【问题描述】:

你好! 今天我学习了for xml path在mssql中连接字符串的技术。由于我从未在 mssql 中使用过 xml,而 google 也没有帮助,所以我需要问你。

让我们想象一下默认情况。我们需要连接表格中的一些字符串:

declare @xmlRepNames xml = (
    select          
        ', [' + report_name + ']'
    from (
        select distinct
            report_order,
            report_name
        from #report
    ) x
    order by
        report_order
    for xml path(''), type)

select
    stuff((select @xmlRepNames.value('.', 'nvarchar(max)')), 1, 1, '')

所以我是这样的:

[str1], [str2], [strn]

好的。它工作正常。但我有两个非常相似的连接块。不同之处在于结果字符串的样子:

  • [str1], [str2], [strn]
  • isnull([str1], 0) as [str1], isnull([str2], 0) as [str2], isnull([strn], 0) as [strn]

所以我可以使用不同的字符串构造函数编写 2 个非常相似的代码块(已经完成,顺便说一句),或者尝试将以前的代码扩展为包含 2 种构造函数的 xml 变量,然后通过 xml 节点类型连接。第二种方式我遇到了一些问题 - 我写了这个:

declare @xmlRepNames xml = (
    select
        ', [' + report_name + ']' as name,
        ', isnull([' + report_name + '], 0) as [' + report_name + ']' as res
    from (
        select distinct
            report_order,
            report_name
        from #report
    ) x
    order by
        report_order
    for xml path(''), type)

select
    stuff((select @xmlRepNames.value('/name', 'nvarchar(max)')), 1, 1, ''),
    stuff((select @xmlRepNames.value('/res', 'nvarchar(max)')), 1, 1, '')

但它会引发错误"XQuery [value()]: 'value()' requires a singleton (or empty sequence), found operand of type 'xdt:untypedAtomic *'"
要替换,例如,'/name''/name[1]' 或任何其他 '/name[x]',将只返回第 x 个“名称”记录,但不是所有连接的“名称”记录。
[问题]:是否可以像我想要的那样以第二种方式解决问题,如果可以,那么如何解决?
[免责声明]:问题是'现在对我来说真的不是很严重(第一种方式有点丑但也很好),但是如何过来似乎很有趣:) 谢谢!

【问题讨论】:

标签: sql sql-server-2008 string-concatenation for-xml-path


【解决方案1】:

您的子查询不能返回两个值。如果您只想连接字符串,则根本不需要 xml 数据类型。您可以在单个语句中执行 stuff() 和子查询:

declare @Rep1Names nvarchar(max) = (
    stuff((select ', [' + report_name + ']' as name
           from (select distinct report_order, report_name
                 from #report
                ) x
           order by report_order
           for xml path('')
          )
         ), 1, 1, '');

declare @Rep2Names nvarchar(max) = (
    stuff(select ', isnull([' + report_name + '], 0) as [' + report_name + ']' as res
           from (select distinct report_order, report_name
                 from #report
                ) x
           order by report_order
           for xml path('')
          )
   ), 1, 1, '');

【讨论】:

    【解决方案2】:

    好的,所以我对 Gordon Linoff 建议的方式并不完全满意,因为我发现这种问题对我来说确实存在,所以我在这里添加了另一个解决方案,而不使用 for xml path

    declare
        @pivot_sequence nvarchar(max),
        @columns_sequence nvarchar(max)
    
    select
        @pivot_sequence = coalesce(@pivot_sequence + ', [', '[') 
            + col_name + ']',
        @columns_sequence = coalesce(@columns_sequence + ', ', '')
            + 'isnull([' + col_name + '], 0) as [' + col_name + ']'
    from some_table
    order by
        /* some_columns if needed to order concatenation */
    

    显然,它的工作速度会慢得多,但在行数不多的情况下,它不会对性能产生重大影响。在我的情况下,我有动态数据透视查询,这些字符串是为它构建的 - 我不会在数据透视中有很多列,所以这对我来说很好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-16
      • 1970-01-01
      • 2011-03-11
      • 2016-12-26
      • 2011-06-27
      • 2014-10-29
      • 2020-05-18
      • 1970-01-01
      相关资源
      最近更新 更多