359

MySQL ベースのアプリを Microsoft SQL Server 2005 に移行しようとしています (選択によるものではありませんが、それが人生です)。

元のアプリでは、ほぼ完全に ANSI-SQL 準拠のステートメントを使用していましたが、1 つの重要な例外があり、MySQL のgroup_concat関数をかなり頻繁に使用していました。

group_concat、ちなみに、これを行います: たとえば、従業員名とプロジェクトのテーブルが与えられた場合...

SELECT empName, projID FROM project_members;

戻り値:

ANDY   |  A100
ANDY   |  B391
ANDY   |  X010
TOM    |  A100
TOM    |  A510

... そして、これが group_concat で得られるものです:

SELECT 
    empName, group_concat(projID SEPARATOR ' / ') 
FROM 
    project_members 
GROUP BY 
    empName;

戻り値:

ANDY   |  A100 / B391 / X010
TOM    |  A100 / A510

だから私が知りたいのは、たとえば、SQL Serverでの機能をエミュレートするユーザー定義関数を書くことは可能group_concatですか?

私はUDF、ストアドプロシージャ、またはそのようなものを使用した経験がほとんどなく、単純なSQLであるため、説明が多すぎると誤解してください:)

4

13 に答える 13

174

これを行う簡単な方法はありません。しかし、そこにはたくさんのアイデアがあります。

私が見つけた最高のもの

SELECT table_name, LEFT(column_names , LEN(column_names )-1) AS column_names
FROM information_schema.columns AS extern
CROSS APPLY
(
    SELECT column_name + ','
    FROM information_schema.columns AS intern
    WHERE extern.table_name = intern.table_name
    FOR XML PATH('')
) pre_trimmed (column_names)
GROUP BY table_name, column_names;

または、データに次のような文字が含まれている可能性がある場合に正しく機能するバージョン<

WITH extern
     AS (SELECT DISTINCT table_name
         FROM   INFORMATION_SCHEMA.COLUMNS)
SELECT table_name,
       LEFT(y.column_names, LEN(y.column_names) - 1) AS column_names
FROM   extern
       CROSS APPLY (SELECT column_name + ','
                    FROM   INFORMATION_SCHEMA.COLUMNS AS intern
                    WHERE  extern.table_name = intern.table_name
                    FOR XML PATH(''), TYPE) x (column_names)
       CROSS APPLY (SELECT x.column_names.value('.', 'NVARCHAR(MAX)')) y(column_names) 
于 2009-01-16T18:22:53.770 に答える
172

私はパーティーに少し遅れているかもしれませんが、この方法は私にはうまくいき、COALESCE 方法よりも簡単です。

SELECT STUFF(
             (SELECT ',' + Column_Name 
              FROM Table_Name
              FOR XML PATH (''))
             , 1, 1, '')
于 2011-05-12T17:20:27.863 に答える
52

SQL Server 2017には新しい集計関数が導入されています

STRING_AGG ( expression, separator).

文字列式の値を連結し、それらの間に区切り値を配置します。文字列の末尾にセパレータは追加されません。

連結された要素は、追加することで並べ替えることができますWITHIN GROUP (ORDER BY some_expression)

バージョン 2005 ~ 2016では、通常、受け入れられた回答で XML メソッドを使用します。

ただし、これは状況によっては失敗する可能性があります。たとえば、連結するデータに次のものが含まれているCHAR(29)場合

FOR XML はデータをシリアル化できませんでした ... XML で許可されていない文字 (0x001D) が含まれているためです。

すべての文字を処理できるより堅牢な方法は、CLR 集計を使用することです。ただし、連結された要素に順序付けを適用することは、このアプローチではより困難です。

変数への割り当て方法は保証されていないため、製品コードでは避ける必要があります。

于 2016-11-19T11:01:53.337 に答える
51

おそらく今は手遅れで利益を得ることができませんが、これは物事を行うための最も簡単な方法ではありませんか?

SELECT     empName, projIDs = replace
                          ((SELECT Surname AS [data()]
                              FROM project_members
                              WHERE  empName = a.empName
                              ORDER BY empName FOR xml path('')), ' ', REQUIRED SEPERATOR)
FROM         project_members a
WHERE     empName IS NOT NULL
GROUP BY empName
于 2010-02-24T06:24:11.757 に答える
34

Github のGROUP_CONCATプロジェクトを見てください。まさにあなたが探しているものを実行していると思います。

このプロジェクトには、MySQL GROUP_CONCAT 関数と同様の機能を集合的に提供する一連の SQLCLR ユーザー定義集計関数 (SQLCLR UDA) が含まれています。必要な機能に基づいて最高のパフォーマンスを確保するための複数の機能があります...

于 2012-12-21T18:57:05.523 に答える
11

複数のプロジェクト マネージャーがいるプロジェクトのすべてのプロジェクト マネージャー名を連結するには、次のように記述します。

SELECT a.project_id,a.project_name,Stuff((SELECT N'/ ' + first_name + ', '+last_name FROM projects_v 
where a.project_id=project_id
 FOR
 XML PATH(''),TYPE).value('text()[1]','nvarchar(max)'),1,2,N''
) mgr_names
from projects_v a
group by a.project_id,a.project_name
于 2011-06-28T15:00:11.340 に答える
8

これらを試してみましたが、MS SQL Server 2005 での目的のためには、xaprbで見つけた以下が最も役に立ちました。

declare @result varchar(8000);

set @result = '';

select @result = @result + name + ' '

from master.dbo.systypes;

select rtrim(@result);

あなたが言ったように@Mark私に問題を引き起こしたのはスペース文字でした。

于 2010-10-07T17:52:12.537 に答える
6

J Hardimanの答えについて、どうですか:

SELECT empName, projIDs=
  REPLACE(
    REPLACE(
      (SELECT REPLACE(projID, ' ', '-somebody-puts-microsoft-out-of-his-misery-please-') AS [data()] FROM project_members WHERE empName=a.empName FOR XML PATH('')), 
      ' ', 
      ' / '), 
    '-somebody-puts-microsoft-out-of-his-misery-please-',
    ' ') 
  FROM project_members a WHERE empName IS NOT NULL GROUP BY empName

ところで、「姓」の使い方はタイプミスですか、それともここで概念を理解していませんか?

とにかく、おかげでかなりの時間を節約できました:)

于 2010-08-16T21:16:02.417 に答える
0

私の仲間の Google 社員のために、より複雑なソリューションにしばらく苦労した後、私のために働いた非常にシンプルなプラグアンドプレイ ソリューションを次に示します。

SELECT
distinct empName,
NewColumnName=STUFF((SELECT ','+ CONVERT(VARCHAR(10), projID ) 
                     FROM returns 
                     WHERE empName=t.empName FOR XML PATH('')) , 1 , 1 , '' )
FROM 
returns t

ID を文字列として連結するために、ID を VARCHAR に変換する必要があることに注意してください。それを行う必要がない場合は、さらに単純なバージョンを次に示します。

SELECT
distinct empName,
NewColumnName=STUFF((SELECT ','+ projID
                     FROM returns 
                     WHERE empName=t.empName FOR XML PATH('')) , 1 , 1 , '' )
FROM 
returns t

これに対するすべての功績は次のとおりです 。 sql-server?forum=transactsql

于 2019-03-20T20:04:11.393 に答える