SQL Serverで複数行のテキストを単一のテキスト文字列に連結する方法は?


1913

3つの行を持つ名前を保持するデータベーステーブルを考えます。

Peter
Paul
Mary

これを単一の文字列に変換する簡単な方法はありPeter, Paul, Maryますか?


26
SQL Serverに固有の回答については、この質問を試してください。
Matt Hamilton、

17
MySQLについては、この回答からGroup_Concatをチェックしてください
Pykler

26
SQL Serverの次のバージョンで、複数行の文字列の連結をFOR XML PATHの煩わしさなしにエレガントに解決する新機能を提供してほしいと思います。
ピートアルビン

4
SQLではありませんが、これが1回限りの場合は、リストをこのブラウザー内ツールconvert.town/column-to-comma-separated-listに
Stack Man

3
Oracleでは、11g r2のLISTAGG(COLUMN_NAME)を使用してから、同じことを行うWM_CONCAT(COLUMN_NAME)と呼ばれるサポートされていない関数を使用できます。
Richard

回答:


1432

SQL Server 2017またはAzureを使用している場合は、Mathieu Rendaの回答を参照してください。

1対多の関係で2つのテーブルを結合しようとしたときにも、同様の問題が発生しました。SQL 2005では、XML PATHメソッドが行の連結を非常に簡単に処理できることがわかりました。

というテーブルがある場合 STUDENTS

SubjectID       StudentName
----------      -------------
1               Mary
1               John
1               Sam
2               Alaina
2               Edward

私が期待した結果は:

SubjectID       StudentName
----------      -------------
1               Mary, John, Sam
2               Alaina, Edward

私は以下を使用しましたT-SQL

SELECT Main.SubjectID,
       LEFT(Main.Students,Len(Main.Students)-1) As "Students"
FROM
    (
        SELECT DISTINCT ST2.SubjectID, 
            (
                SELECT ST1.StudentName + ',' AS [text()]
                FROM dbo.Students ST1
                WHERE ST1.SubjectID = ST2.SubjectID
                ORDER BY ST1.SubjectID
                FOR XML PATH ('')
            ) [Students]
        FROM dbo.Students ST2
    ) [Main]

最初にカンマを連結し、最初のカンマsubstringをスキップしてサブクエリを実行する必要がない場合は、よりコンパクトな方法で同じことを実行できます。

SELECT DISTINCT ST2.SubjectID, 
    SUBSTRING(
        (
            SELECT ','+ST1.StudentName  AS [text()]
            FROM dbo.Students ST1
            WHERE ST1.SubjectID = ST2.SubjectID
            ORDER BY ST1.SubjectID
            FOR XML PATH ('')
        ), 2, 1000) [Students]
FROM dbo.Students ST2

13
素晴らしいソリューション。HTMLのような特殊文字を処理する必要がある場合は、以下が役立ちます。Rob Farley:FOR XML PATH( '')で特殊文字を処理します

10
名前に<or などのXML文字が含まれている場合、これは機能しないよう&です。@BenHinmanのコメントを参照してください。
サム

23
注意:この方法は、文書化されていないの動作に依存していますFOR XML PATH ('')。つまり、パッチやアップデートによってこの機能が変更される可能性があるため、信頼性があると見なすべきではありません。それは基本的に非推奨の機能に依存しています。
ベーコンビット

26
@Whelkaholism要点は、FOR XML任意の文字列を連結するのではなく、XMLを生成することです。それはエスケープだからこそ &<および>(XMLエンティティコードに&amp;&lt;&gt;)。私はそれがまた脱出すると仮定"して'まで&quot;&apos;同様の属性に。それはだではない GROUP_CONCAT()string_agg()array_agg()listagg()あなたは一種のmake、それはそれを行うことができる場合であっても、など。我々はすべきであるマイクロソフトが適切な機能を実装厳しい私たちの時間を過ごすこと。
ベーコンビット

13
朗報:MS SQL Serverがstring_aggv.Next に追加される予定です。そして、これらすべてがなくなる可能性があります。
Jason C

1009

この回答は予期しない結果を返す可能性があります一貫した結果を得るには、他の回答で詳述されているFOR XML PATHメソッドの1つを使用してください。

使用COALESCE

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + Name 
FROM People

ほんの一部の説明(この回答は比較的規則的な見解を持っているように見えるため):

  • Coalesceは、実際には次の2つのことを実行するのに役立つチートです。

1)@Names空の文字列値で初期化する必要はありません。

2)最後に余分なセパレーターを取り除く必要はありません。

  • 行が持っている場合、溶液は、上記の誤った結果を与えるNULLがある場合(name値をNULLNULLになります@Names NULLをその行の後、次の行が再び空の文字列としてオーバーを開始します。簡単に二つのうちの一つで固定しますソリューション:
DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + Name
FROM People
WHERE Name IS NOT NULL

または:

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(@Names + ', ', '') + 
    ISNULL(Name, 'N/A')
FROM People

必要な動作に応じて(最初のオプションはNULLを除外するだけですが、2番目のオプションはそれらをマーカーメッセージでリストに保持します['N / A'を適切なものに置き換えます))。


72
明確にするために、合体はリストの作成とは関係なく、NULL値が含まれていないことを確認するだけです。
Graeme Perrow、

17
@Graeme Perrow NULL値は除外されません(そのためにはWHEREが必要です。これは、入力値の1つがNULLの場合、結果失われます)。これは、次の理由でこのアプローチで必要になります。NULL +非NULL-> NULL非NULL + NULL-> NULL; また、@ NameはデフォルトでNULLであり、実際には、そのプロパティはここで暗黙のセンチネルとして使用され、 '、'を追加するかどうかを決定します。

62
この連結方法は、SQL Serverが特定のプランでクエリを実行することに依存していることに注意してください。私はこのメソッドを使用して(ORDER BYを追加して)検出されました。少数の行を処理していた場合は問題なく動作しましたが、SQL Serverはより多くのデータを使用して別のプランを選択したため、連結されていない最初の項目が選択されました。参照この記事 Anith上院議員による
fbarber

17
このメソッドは、tSQL変数を使用するため、選択リストまたはwhere節でサブクエリとして使用できません。そのような場合、@ Ritesh
R. Schreursが

11
これは信頼できる連結方法ではありません。これはサポートされていないため、使用しないでください(Microsoftごとに、support.microsoft.com / en-us/kb/287515connect.microsoft.com/SQLServer/Feedback/Details/704389など)。警告なしに変更される可能性があります。で説明したXML PATHの技術を使用しstackoverflow.com/questions/5031204/...:私はもっとここに書いたmarc.durdin.net/2015/07/...
マルク・Durdin

454

SQL Server 2017以降およびSQL Azure:STRING_AGG

SQL Serverの次のバージョンから、変数やXMLウィッチャリに頼ることなく、最終的に行全体を連結できます。

STRING_AGG(Transact-SQL)

グループ化なし

SELECT STRING_AGG(Name, ', ') AS Departments
FROM HumanResources.Department;

グループ化:

SELECT GroupName, STRING_AGG(Name, ', ') AS Departments
FROM HumanResources.Department
GROUP BY GroupName;

グループ化とサブソートを使用

SELECT GroupName, STRING_AGG(Name, ', ') WITHIN GROUP (ORDER BY Name ASC) AS Departments
FROM HumanResources.Department 
GROUP BY GroupName;

2
また、CLRソリューションとは異なり、並べ替えを制御できます。
キヤノン

STRING_AGGには4000文字の表示制限があるようです
InspiredBy

GROUP BYがない場合にソートを行う方法はありますか(「グループ化なし」の例のように)?
RuudvK

更新:私はなんとか次のことを実行できましたが、よりクリーンな方法はありますか?SELECT STRING_AGG(Name、 '、')AS Departments FROM(SELECT TOP 100000 Name FROM FROM HumanResources.Department ORDER BY Name)D;
RuudvK

362

XML data()MS SQL Serverのコマンドでまだ表示されていない方法の1つは次のとおりです。

FNameという1つの列を持つNameListというテーブルを想定します。

SELECT FName + ', ' AS 'data()' 
FROM NameList 
FOR XML PATH('')

戻り値:

"Peter, Paul, Mary, "

余分なコンマのみを処理する必要があります。

編集: @NReilinghのコメントから採用されているように、次のメソッドを使用して末尾のコンマを削除できます。同じテーブル名と列名を想定します。

STUFF(REPLACE((SELECT '#!' + LTRIM(RTRIM(FName)) AS 'data()' FROM NameList
FOR XML PATH('')),' #!',', '), 1, 2, '') as Brands

15
神聖なそれは素晴らしいです!単独で実行すると、例のように結果はハイパーリンクとしてフォーマットされ、クリックすると(SSMSで)データを含む新しいウィンドウが開きますが、より大きなクエリの一部として使用すると、文字列として表示されます。ひもですか?または、このデータを使用するアプリケーションで別の方法で処理する必要があるのはxmlですか?
Ben

10
このアプローチでは、<や>などの文字もXMLエスケープします。したがって、 '<b>' + FName + '</ b>'を選択すると、「&lt; b&gt;ジョン&lt; / b&gt;&lt; b&gt;ポール...」
ルカシュランスキー

8
きちんとしたソリューション。追加しなくても、+ ', '連結された各要素の間にスペースが1つ追加されることに気づきました。
バオダード2014年

8
@Baodadそれは契約の一部のようです。追加したトークン文字を置き換えることで回避できます。たとえば、これは、任意の長さのための完全なカンマ区切りのリストないSELECT STUFF(REPLACE((SELECT '#!'+city AS 'data()' FROM #cityzip FOR XML PATH ('')),' #!',', '),1,2,'')
NReilingh

1
うわー、実際に私のテストでdata()と置換を使用すると、パフォーマンスが向上します。超変。
NReilingh 2016

306

SQL Server 2005の

SELECT Stuff(
  (SELECT N', ' + Name FROM Names FOR XML PATH(''),TYPE)
  .value('text()[1]','nvarchar(max)'),1,2,N'')

SQL Server 2016で

FOR JSON構文を使用できます

すなわち

SELECT per.ID,
Emails = JSON_VALUE(
   REPLACE(
     (SELECT _ = em.Email FROM Email em WHERE em.Person = per.ID FOR JSON PATH)
    ,'"},{"_":"',', '),'$[0]._'
) 
FROM Person per

そして結果は

Id  Emails
1   abc@gmail.com
2   NULL
3   def@gmail.com, xyz@gmail.com

これは、データに無効なXML文字が含まれている場合でも機能します

'"},{"_":"'データが含まれ'"},{"_":"',ている場合はエスケープされるため、これは安全です"},{\"_\":\"

', '任意の文字列セパレーターで置き換えることができます


SQL Server 2017では、Azure SQL Database

新しいSTRING_AGG関数を使用できます


3
先頭の2文字をnixするためのSTUFF関数の活用。
David

3
「<label>として」を追加することで、選択リストで簡単に使用できるため、このソリューションが最も気に入っています。@Riteshのソリューションでこれを行う方法がわかりません。
R. Schreurs 2013

13
このオプションには、また、アンエスケープXMLのreserverd文字扱うので、これが受け入れ答えよりも優れている<>&、などこれはFOR XML PATH('')自動的にエスケープしますが。
BateTech 2014

このことは問題を解決して素晴らしい反応であり、今、私は私が2017 /アズールを使用することがしたいSQLの異なるバージョンに物事の最善の方法を提供します
クリス・ウォード

120

MySQLには関数GROUP_CONCAT()があり、これを使用して複数の行の値を連結できます。例:

SELECT 1 AS a, GROUP_CONCAT(name ORDER BY name ASC SEPARATOR ', ') AS people 
FROM users 
WHERE id IN (1,2,3) 
GROUP BY a

うまくいきます。しかし、私が使用するSEPARATOR '", "'と、最後のエントリの最後にいくつかの文字が表示されなくなります。なぜこれが起こるのですか?
gooleem

@gooleemどういう意味かはわかりませんが、この関数はセパレータをアイテムの間に置くだけで、後ろには置きません。それが答えでない場合は、新しい質問を投稿することをお勧めします。
Darryl Hein

@DarrylHein私のニーズのために、私は上記のようにセパレータを使用しました。しかし、これは出力の最後でいくつかの文字をカットします。これは非常に奇妙で、バグのようです。私には解決策がありません、私はただ回避しました。
gooleem 16

基本的に動作します。二つのことを考慮すること:1)あなたのコラムではない場合CHAR、あなたはそれをキャストする必要があり、例えば経てGROUP_CONCAT( CAST(id AS CHAR(8)) ORDER BY id ASC SEPARATOR ',')2)あなたは多くの値が来ている場合、あなたは増加するはずgroup_concat_max_lenで書かれたようstackoverflow.com/a/1278210/1498405
hardmooth

58

COALESCEの使用- 詳細はここから

例として:

102

103

104

次に、SQLサーバーで以下のコードを記述します。

Declare @Numbers AS Nvarchar(MAX) -- It must not be MAX if you have few numbers 
SELECT  @Numbers = COALESCE(@Numbers + ',', '') + Number
FROM   TableName where Number IS NOT NULL

SELECT @Numbers

出力は次のようになります:

102,103,104

2
これは、FOR XMLが提示するエンコードの問題を回避するため、本当に最良のソリューションIMOです。私が使用しDeclare @Numbers AS Nvarchar(MAX)、それはうまくいきました。使用しないことをお勧めする理由を教えてください。
EvilDr 2016

7
このソリューションはすでに8年前に投稿されています!stackoverflow.com/a/194887/986862
Andre Figueiredo

このクエリが返されるのはなぜですか?キリル文字の代わりに記号?これは単に出力の問題ですか?
Akmal Salikhov 2017

48

Postgres配列は素晴らしいです。例:

テストデータを作成します。

postgres=# \c test
You are now connected to database "test" as user "hgimenez".
test=# create table names (name text);
CREATE TABLE                                      
test=# insert into names (name) values ('Peter'), ('Paul'), ('Mary');                                                          
INSERT 0 3
test=# select * from names;
 name  
-------
 Peter
 Paul
 Mary
(3 rows)

それらを配列に集約します。

test=# select array_agg(name) from names;
 array_agg     
------------------- 
 {Peter,Paul,Mary}
(1 row)

配列をコンマ区切りの文字列に変換します。

test=# select array_to_string(array_agg(name), ', ') from names;
 array_to_string
-------------------
 Peter, Paul, Mary
(1 row)

完了

PostgreSQL 9.0以降はさらに簡単です。


:あなたは複数の列が必要な場合は、例えば括弧内その従業員IDは、連結演算子を使用 select array_to_string(array_agg(name||'('||id||')'
リチャード・フォックス


46

Oracle 11gリリース2はLISTAGG関数をサポートしています。ドキュメントはこちら

COLUMN employees FORMAT A50

SELECT deptno, LISTAGG(ename, ',') WITHIN GROUP (ORDER BY ename) AS employees
FROM   emp
GROUP BY deptno;

    DEPTNO EMPLOYEES
---------- --------------------------------------------------
        10 CLARK,KING,MILLER
        20 ADAMS,FORD,JONES,SCOTT,SMITH
        30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD

3 rows selected.

警告

結果の文字列が4000文字を超える可能性がある場合は、この関数の実装に注意してください。例外をスローします。その場合は、例外を処理するか、結合された文字列が4000文字を超えないようにする独自の関数をロールする必要があります。


1
古いバージョンのOracleでは、wm_concatが最適です。その使用法は、Alexによるリンクギフトで説明されています。Thnks Alex!
toscanelli

LISTAGG完璧に動作します!ここにリンクされているドキュメントを読んでください。wm_concatバージョン12c以降は削除されました。
asgs

34

SQL Server 2005以降では、以下のクエリを使用して行を連結します。

DECLARE @t table
(
    Id int,
    Name varchar(10)
)
INSERT INTO @t
SELECT 1,'a' UNION ALL
SELECT 1,'b' UNION ALL
SELECT 2,'c' UNION ALL
SELECT 2,'d' 

SELECT ID,
stuff(
(
    SELECT ','+ [Name] FROM @t WHERE Id = t.Id FOR XML PATH('')
),1,1,'') 
FROM (SELECT DISTINCT ID FROM @t ) t

2
私は、値のようなXMLシンボル含まれているとき、これは失敗したと考えている<かを&
Sam

28

自宅ではSQL Serverにアクセスできないので、ここの構文は多分わかりますが、多かれ少なかれです。

DECLARE @names VARCHAR(500)

SELECT @names = @names + ' ' + Name
FROM Names

11
@namesをnull以外の何かに初期化する必要があります。そうしないと、全体を通してNULLになります。区切り文字(不要なものを含む)も処理する必要があります
マークグラベル

3
このアプローチ(私はいつも使用しています)の唯一の問題は、それを埋め込むことができないことです
ekkis

1
先頭の空白を取り除くためにはにクエリを変更するSELECT @names = @names + CASE WHEN LEN(@names)=0 THEN '' ELSE ' ' END + Name FROM Names
天バンHeerden

また、あなたは名前がnullでないことを確認する必要があり、あなたがやってそれを行うことができますSELECT @names = @names + ISNULL(' ' + Name, '')
Vita1ij

28

再帰的なCTEソリューションが提案されましたが、コードは提供されませんでした。以下のコードは、再帰CTEの例です。結果は質問と一致しますが、データは指定された説明とは完全には一致しません。これは、テーブル内のすべての行ではなく、行のグループに対して実際に実行することを想定しているためです。表のすべての行に一致するように変更することは、読者の練習問題として残します。

;WITH basetable AS (
    SELECT
        id,
        CAST(name AS VARCHAR(MAX)) name, 
        ROW_NUMBER() OVER (Partition BY id ORDER BY seq) rw, 
        COUNT(*) OVER (Partition BY id) recs 
    FROM (VALUES
        (1, 'Johnny', 1),
        (1, 'M', 2), 
        (2, 'Bill', 1),
        (2, 'S.', 4),
        (2, 'Preston', 5),
        (2, 'Esq.', 6),
        (3, 'Ted', 1),
        (3, 'Theodore', 2),
        (3, 'Logan', 3),
        (4, 'Peter', 1),
        (4, 'Paul', 2),
        (4, 'Mary', 3)
    ) g (id, name, seq)
),
rCTE AS (
    SELECT recs, id, name, rw
    FROM basetable
    WHERE rw = 1

    UNION ALL

    SELECT b.recs, r.ID, r.name +', '+ b.name name, r.rw + 1
    FROM basetable b
    INNER JOIN rCTE r ON b.id = r.id AND b.rw = r.rw + 1
)
SELECT name
FROM rCTE
WHERE recs = rw AND ID=4

1
flabbergastedの場合:このクエリは、一時的なベーステーブルに12行(3列)を挿入し、再帰的な共通テーブル式(rCTE)を作成して、name 列をsの4つのグループのコンマ区切り文字列にフラット化しますid。一見すると、これはSQL Serverの他のほとんどのソリューションが行うよりも多くの作業だと思います。
knb 2017

2
@knb:それが賞賛、非難、または単に驚きであるかどうかはわかりません。ベーステーブルは、自分の例が実際に機能することを望んでいるため、質問とはまったく関係ありません。
jmoreno 2017

26

PostgreSQL 9.0以降、これは非常に簡単です。

select string_agg(name, ',') 
from names;

9.0より前のバージョンではarray_agg()、hgmnzで示されているように使用できます。


:text型でない列でこれを行うには、型キャストを追加する必要がありますSELECT string_agg(non_text_type::text, ',') FROM table
トーベンKohlmeier

@TorbenKohlmeier:非文字列(例:整数、10進数)にのみ必要です。varcharまたは、char
a_horse_with_no_nameで

26

最終結果を保持する変数を作成し、そのように選択する必要があります。

最も簡単なソリューション

DECLARE @char VARCHAR(MAX);

SELECT @char = COALESCE(@char + ', ' + [column], [column]) 
FROM [table];

PRINT @char;


18

XMLを使用すると、行をコンマで区切るのに役立ちました。余分なコンマについては、SQL Serverの置換機能を使用できます。カンマを追加する代わりに、AS 'data()'を使用すると、行がスペースで連結されます。これは、後で記述する構文としてカンマで置き換えることができます。

REPLACE(
        (select FName AS 'data()'  from NameList  for xml path(''))
         , ' ', ', ') 

2
これは私の意見では、ここでの最良の答えです。別のテーブルに結合する必要がある場合、変数の宣言を使用するのはよくありません。これは便利で短いものです。よくできました。
David Roussel

7
FNameデータに既にスペースが含まれている場合、たとえば "My Name"の場合はうまく機能しません
binball

本当にそれはms-sql 2016で私のために働いていますREPLACE(を選択してください、 ')as allBrands
Rejwanul Reja '28

17

追加のカンマのない、すぐに使えるソリューション:

select substring(
        (select ', '+Name AS 'data()' from Names for xml path(''))
       ,3, 255) as "MyList"

空のリストはNULL値になります。通常、リストをテーブルの列またはプログラム変数に挿入します。最大長255を必要に応じて調整します。

(DiwakarとJens Frandsenは良い答えを提供しましたが、改善が必要です。)


これを使用する場合、コンマの前にスペースがあります:(
slayernoah

1
余分なスペースが必要ない場合は、に置き換え', '','ください。
Daniel Reis

13
SELECT STUFF((SELECT ', ' + name FROM [table] FOR XML PATH('')), 1, 2, '')

これがサンプルです:

DECLARE @t TABLE (name VARCHAR(10))
INSERT INTO @t VALUES ('Peter'), ('Paul'), ('Mary')
SELECT STUFF((SELECT ', ' + name FROM @t FOR XML PATH('')), 1, 2, '')
--Peter, Paul, Mary

10
DECLARE @Names VARCHAR(8000)
SELECT @name = ''
SELECT @Names = @Names + ',' + Names FROM People
SELECT SUBSTRING(2, @Names, 7998)

これは、最初に浮遊コンマを置きます。

ただし、他の列が必要な場合、または子テーブルをCSVにするには、これをスカラーユーザー定義フィールド(UDF)でラップする必要があります。

SELECT句で相関サブクエリとしてXMLパスを使用することもできます(ただし、Googleは自宅で仕事をしていないため、仕事に戻るまで待つ必要があります:-)


10

他の回答では、回答を読む人は、車両や学生などの特定のドメインテーブルを知っている必要があります。ソリューションをテストするには、テーブルを作成してデータを入力する必要があります。

以下は、SQL Serverの「Information_Schema.Columns」テーブルを使用する例です。このソリューションを使用すると、テーブルを作成したりデータを追加したりする必要がありません。この例では、データベース内のすべてのテーブルの列名のコンマ区切りリストを作成します。

SELECT
    Table_Name
    ,STUFF((
        SELECT ',' + Column_Name
        FROM INFORMATION_SCHEMA.Columns Columns
        WHERE Tables.Table_Name = Columns.Table_Name
        ORDER BY Column_Name
        FOR XML PATH ('')), 1, 1, ''
    )Columns
FROM INFORMATION_SCHEMA.Columns Tables
GROUP BY TABLE_NAME 

7

Oracle DBの場合は、次の質問を参照してください。 、ストアドプロシージャを作成せずに、複数の行を1つに連結するにはどうすればよいですか。

最良の答えは、Oracle 11gリリース2以降で使用可能な組み込みのLISTAGG()関数を使用した@Emmanuelによるものと思われます。

SELECT question_id,
   LISTAGG(element_id, ',') WITHIN GROUP (ORDER BY element_id)
FROM YOUR_TABLE;
GROUP BY question_id

@ user762952が指摘したように、そしてOracleのドキュメントによるとhttp://www.oracle-base.com/articles/misc/string-aggregation-techniques.php、WM_CONCAT()関数もオプションです。安定しているように見えますが、OracleはアプリケーションSQLに使用しないことを明確に推奨しているため、自己責任で使用してください。

それ以外に、独自の関数を作成する必要があります。上記のOracleドキュメントには、その方法に関するガイドがあります。


7

null値を回避するには、CONCAT()を使用できます

DECLARE @names VARCHAR(500)
SELECT @names = CONCAT(@names, ' ', name) 
FROM Names
select @names

CONCATが機能する理由を知っておくとよいでしょう。MSDNへのリンクがいいです。
リバースエンジニア、

7

ダナの答えの優雅さが本当に好きだった。それを完全にしたかっただけです。

DECLARE @names VARCHAR(MAX)
SET @names = ''

SELECT @names = @names + ', ' + Name FROM Names 

-- Deleting last two symbols (', ')
SET @sSql = LEFT(@sSql, LEN(@sSql) - 1)

最後の2つの記号 '、'を削除する場合は、名前の後に '、'を追加する必要があります( 'SELECT \ @names = \ @names + Name +'、 'FROM Names')。そうすれば、最後の2文字は常に「、」になります。
JT_

私の場合、先頭のコンマを取り除く必要があったので、クエリを変更して、SELECT @names = @names + CASE WHEN LEN(@names)=0 THEN '' ELSE ', ' END + Name FROM Names後で切り捨てる必要がないようにします。
Tian van Heerden 2016年

6

この回答を機能させるには、サーバーで何らかの特権が必要です。

アセンブリはあなたにとって良いオプションです。それを作成する方法を説明する多くのサイトがあります。私は非常によく説明されていると思います一つはこれです1

必要に応じて、私はすでにアセンブリを作成しています。DLLをここからダウンロードできます

ダウンロードしたら、SQL Serverで次のスクリプトを実行する必要があります。

CREATE Assembly concat_assembly 
   AUTHORIZATION dbo 
   FROM '<PATH TO Concat.dll IN SERVER>' 
   WITH PERMISSION_SET = SAFE; 
GO 

CREATE AGGREGATE dbo.concat ( 

    @Value NVARCHAR(MAX) 
  , @Delimiter NVARCHAR(4000) 

) RETURNS NVARCHAR(MAX) 
EXTERNAL Name concat_assembly.[Concat.Concat]; 
GO  

sp_configure 'clr enabled', 1;
RECONFIGURE

アセンブリへのパスがサーバーにアクセスできることを確認します。すべてのステップを正常に完了したので、次のような関数を使用できます。

SELECT dbo.Concat(field1, ',')
FROM Table1

それが役に立てば幸い!!!


1
DLLリンクは404エラーです。これにアセンブリを使用するのはやり過ぎです。SQL Serverのベストアンサーをご覧ください。
隣接

6

MySQLの完全な例:

多くのデータを持つことができるユーザーがいて、すべてのユーザーのデータをリストで確認できる出力が必要です。

結果:

___________________________
| id   |  rowList         |
|-------------------------|
| 0    | 6, 9             |
| 1    | 1,2,3,4,5,7,8,1  |
|_________________________|

テーブル設定:

CREATE TABLE `Data` (
  `id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1;


INSERT INTO `Data` (`id`, `user_id`) VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1),
(6, 0),
(7, 1),
(8, 1),
(9, 0),
(10, 1);


CREATE TABLE `User` (
  `id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


INSERT INTO `User` (`id`) VALUES
(0),
(1);

クエリ:

SELECT User.id, GROUP_CONCAT(Data.id ORDER BY Data.id) AS rowList FROM User LEFT JOIN Data ON User.id = Data.user_id GROUP BY User.id

5

私は通常、SQL Serverで文字列を連結するために次のような選択を使用します。

with lines as 
( 
  select 
    row_number() over(order by id) id, -- id is a line id
    line -- line of text.
  from
    source -- line source
), 
result_lines as 
( 
  select 
    id, 
    cast(line as nvarchar(max)) line 
  from 
    lines 
  where 
    id = 1 
  union all 
  select 
    l.id, 
    cast(r.line + N', ' + l.line as nvarchar(max))
  from 
    lines l 
    inner join 
    result_lines r 
    on 
      l.id = r.id + 1 
) 
select top 1 
  line
from
  result_lines
order by
  id desc

5

nullを処理する場合は、where句を追加するか、最初の句の周りに別のCOALESCEを追加することでそれを行うことができます。

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(COALESCE(@Names + ', ', '') + Name, @Names) FROM People

5

これは私のために働きました(SqlServer 2016):

SELECT CarNamesString = STUFF((
         SELECT ',' + [Name]
            FROM tbl_cars 
            FOR XML PATH('')
         ), 1, 1, '')

これがソースです:https : //www.mytecbits.com/

MySqlのソリューション(このページはGoogleでMySqlに表示されるため)

SELECT [Name],
       GROUP_CONCAT(DISTINCT [Name]  SEPARATOR ',')
       FROM tbl_cars

MySqlドキュメントから



4

これも役に立ちます

create table #test (id int,name varchar(10))
--use separate inserts on older versions of SQL Server
insert into #test values (1,'Peter'), (1,'Paul'), (1,'Mary'), (2,'Alex'), (3,'Jack')

DECLARE @t VARCHAR(255)
SELECT @t = ISNULL(@t + ',' + name, name) FROM #test WHERE id = 1
select @t
drop table #test

戻り値

Peter,Paul,Mary

5
残念ながら、この動作は公式にはサポートされていないようです。MSDNによると、「変数が選択リストで参照されている場合、変数にスカラー値を割り当てるか、SELECTステートメントで1行だけを返す必要があります。」そして、問題を観察した人がいます:sqlmag.com/sql-server/multi-row-variable-assignment-and-order
blueling
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.