17

データベース ビュー (SQL Server 2005) からデータを取得するレポート用の汎用システムを使用しています。このビューでは、1 対多の関係からのデータを 1 つの行にマージする必要があり、このスレッドでpriyanka.sarkarによって説明されているソリューションを使用しました。このソリューションでは、SQLXML を使用してデータをマージします (サブクエリ)。

SELECT STUFF(
    (    SELECT ', ' + Name 
         FROM MyTable _in 
         WHERE _in.ID = _out.ID 
         FOR XML PATH('')),        -- Output multiple rows as one xml type value,
                                   -- without xml tags
    1, 2, '')      -- STUFF: Replace the comma at the beginning with empty string
FROM MyTable _out 
GROUP BY ID        -- Removes duplicates

& これは完全に機能します (パフォーマンスはそれほど高くありません) が、私のデータが SQLXML によってエンコードされた XML (& => など) を取得することを除いて - 結局、XML データは必要ありませんでした。これをトリックとして使用しただけです。エンコードされたデータがレポートに直接送られるように、これをクリーンアップするためにコーディングすることはできません。汎用システムでストアド プロシージャを使用できないため、CURSOR マージまたは COALESCE はここではオプションではありません...

したがって、私が探しているのは、XML を再度デコードできる T-SQL の方法です。それよりも優れているのは、SQLXML によるエンコードを回避することです。明らかに、これを行うストアド関数を作成できますが、組み込みのより安全な方法を好む...

ご協力いただきありがとうございます...

4

2 に答える 2

22
(
select ...
from t
for xml path(''), type
).value('.', 'nvarchar(max)')
于 2012-01-13T20:26:14.767 に答える
5

typeオプションとしてを指定するとfor xml、XPathクエリを使用してXMLタイプをに戻すことができますvarchar。テーブル変数の例:

declare @MyTable table (id int, name varchar(50))

insert @MyTable (id, name) select 1, 'Joel & Jeff'
union all select 1, '<<BIN LADEN>>'
union all select 2, '&&BUSH&&'

考えられる解決策の1つは次のとおりです。

select  b.txt.query('root').value('.', 'varchar(max)')
from    (
        select  distinct id
        from    @MyTable
        ) a
cross apply
        (
            select  CASE ROW_NUMBER() OVER(ORDER BY id) WHEN 1 THEN '' 
                        ELSE ', ' END + name
        from    @MyTable
        where   id = a.id
        order by 
                id
        for xml path(''), root('root'), type
        ) b(txt)

これは印刷されます:

Joel & Jeff, <<BIN LADEN>>
&&BUSH&&

XML変換を使用しない別の方法を次に示します。再帰クエリがあるため、パフォーマンスマイレージは異なる場合があります。Quassnoiのブログからです:

;WITH   with_stats(id, name, rn, cnt) AS
        (
        SELECT  id, name,
                ROW_NUMBER() OVER (PARTITION BY id ORDER BY name),
                COUNT(*) OVER (PARTITION BY id)
        FROM    @MyTable
        ),
        with_concat (id, name, gc, rn, cnt) AS
        (
        SELECT  id, name,
                CAST(name AS VARCHAR(MAX)), rn, cnt
        FROM    with_stats
        WHERE   rn = 1
        UNION ALL
        SELECT  with_stats.id, with_stats.name,
                CAST(with_concat.gc + ', ' + with_stats.name AS VARCHAR(MAX)),
                with_stats.rn, with_stats.cnt
        FROM    with_concat
        JOIN    with_stats
        ON      with_stats.id = with_concat.id
                AND with_stats.rn = with_concat.rn + 1
        )
SELECT  id, gc
FROM    with_concat
WHERE   rn = cnt
OPTION  (MAXRECURSION 0)
于 2010-07-08T10:32:09.580 に答える