3

やあ!今日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]

Ok。それは正常に動作します。しかし、非常によく似た連結ブロックが 2 つあります。違いは、結果の文字列が次のように見えることだけです。

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

したがって、異なる文字列コンストラクターを使用して 2 つの非常によく似たコード ブロック (既に完了しています) を記述したり、前のコードを拡張して 2 種類のコンストラクターを含む xml 変数を作成したり、xml ノード タイプで連結したりできます。2番目の方法でいくつかの問題に遭遇しました-私はこれを書きました:

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'to'/name[1]'またはその他のを置換すると、 '/name[x]'x 番目の 'name' レコードだけが返されますが、連結されたすべての 'name' レコードは返されません。
[質問] : 私が望むように第 2 の方法で問題を解決することは可能ですか。
[免責事項] : 今のところ、問題はそれほど深刻ではありません (最初の方法は少し醜いだけでなく、問題ありません)。

4

2 に答える 2

2

サブクエリで 2 つの値を返すことはできません。文字列を連結したいだけなら、xmlデータ型はまったく必要ありません。stuff()サブクエリとサブクエリを 1 つのステートメントで実行できます。

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, '');
于 2012-12-29T15:39:58.863 に答える
1

わかりましたので、ゴードン・リノフが提案した方法には完全に満足していません。この種の問題が実際にあることがわかったので、使用せずに別の解決策をここに追加します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 */

明らかに、動作ははるかに遅くなりますが、行数が少ない場合は、パフォーマンスに劇的な影響を与えることはありません. 私の場合、動的なピボット クエリがあり、これらの文字列はそのために構築されています。ピボットには多くの列がないので、問題ありません。

于 2013-06-07T11:00:29.760 に答える