2204

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

Peter
Paul
Mary

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

4

47 に答える 47

1585

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 (''), TYPE
            ).value('text()[1]','nvarchar(max)') [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 (''), TYPE
        ).value('text()[1]','nvarchar(max)'), 2, 1000) [Students]
FROM dbo.Students ST2
于 2009-02-13T11:53:52.437 に答える
1096

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

使用COALESCE

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

いくつかの説明(この回答は比較的定期的な見解を得るように思われるため):

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

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

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

  • 上記の解決策では、行の名前の値がNULLの場合、誤った結果が得られます( NULLがある場合、NULLはその行の後にNULL作成し、次の行は空の文字列として最初からやり直します。2つのうちの1つで簡単に修正できます。ソリューション:@Names
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」を適切なものに置き換えます])。

于 2008-10-12T00:18:00.757 に答える
399

XML data()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
于 2011-04-05T21:19:15.560 に答える
336

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 データベース

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

于 2010-09-09T00:08:06.757 に答える
145

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
于 2008-10-12T00:10:14.577 に答える
56

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

いくつかのテストデータを作成します。

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以降、「名前のない馬」による削除された回答からの引用はさらに簡単です。

select string_agg(name, ',') 
from names;
于 2012-08-09T21:20:03.530 に答える
49

Oracle 11g Release 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 文字を超えないようにする独自の関数をロールする必要があります。

于 2012-03-08T16:29:34.373 に答える
37

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
于 2011-07-06T12:46:28.347 に答える
36

再帰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
于 2012-08-09T21:06:05.887 に答える
33

私は自宅でSQLServerにアクセスできないので、ここで構文を推測しますが、多かれ少なかれ次のようになります。

DECLARE @names VARCHAR(500)

SELECT @names = @names + ' ' + Name
FROM Names
于 2008-10-12T00:16:20.167 に答える
23

SQL Server vNext では、これは STRING_AGG 関数で組み込まれます。詳細については、STRING_AGG (Transact-SQL)を参照してください。

于 2016-11-21T11:27:29.307 に答える
20

余分なコンマがない、すぐに使えるソリューション:

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

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

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

于 2012-02-03T10:39:33.463 に答える
19

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

REPLACE(
        (select FName AS 'data()'  from NameList  for xml path(''))
         , ' ', ', ') 
于 2011-04-07T11:16:36.653 に答える
10
DECLARE @Names VARCHAR(8000)
SELECT @name = ''
SELECT @Names = @Names + ',' + Names FROM People
SELECT SUBSTRING(2, @Names, 7998)

これにより、コンマが先頭に配置されます。

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

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

于 2008-10-13T17:24:38.187 に答える
8

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
于 2015-07-22T07:51:12.910 に答える
8

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

DECLARE @names VARCHAR(500)
SELECT @names = CONCAT(@names, ' ', name) 
FROM Names
select @names
于 2015-02-12T12:01:27.810 に答える
8

私はダナの答えの優雅さが本当に好きで、それを完成させたかっただけです。

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

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

-- Deleting last two symbols (', ')
SET @sSql = LEFT(@sSql, LEN(@sSql) - 1)
于 2011-11-21T01:11:57.093 に答える
8

Oracle DB については、次の質問を参照してください:ストアド プロシージャを作成せずに、Oracle で複数の行を 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 ドキュメントには、その方法に関するガイドがあります。

于 2013-05-13T16:02:15.117 に答える
7

この回答が機能するには、サーバー上で何らかの権限が必要です。

アセンブリはあなたにとって良い選択肢です。作り方を解説しているサイトがたくさんあります。私が非常によく説明されていると思うのはこれです

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

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

EXEC sp_configure 'show advanced options', 1
RECONFIGURE;
EXEC sp_configure 'clr strict security', 1;
RECONFIGURE;

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

SQL Server 2017以降、 STRING_AGG関数を使用できるようになりました。

于 2015-05-08T01:39:06.667 に答える
7

null を処理する場合は、where 句を追加するか、最初の句の周りに別の COALESCE を追加して実行できます。

DECLARE @Names VARCHAR(8000) 
SELECT @Names = COALESCE(COALESCE(@Names + ', ', '') + Name, @Names) FROM People
于 2011-07-27T20:05:13.063 に答える
6

私は通常、次のような select を使用して、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
于 2011-07-06T06:58:31.607 に答える
6

Chris Shafferの答えに加えて:

次のように、データが繰り返される可能性がある場合

Tom
Ali
John
Ali
Tom
Mike

持つ代わりにTom,Ali,John,Ali,Tom,Mike

DISTINCT を使用して重複を回避し、次を取得できますTom,Ali,John,Mike

DECLARE @Names VARCHAR(8000)
SELECT DISTINCT @Names = COALESCE(@Names + ',', '') + Name
FROM People
WHERE Name IS NOT NULL
SELECT @Names
于 2019-08-16T00:20:43.600 に答える
5

これも重宝しそう

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
于 2013-10-25T08:14:23.270 に答える
5

オラクルでは、ですwm_concat。この機能は10g 以降のリリースで利用できると思います。

于 2011-06-03T18:14:16.237 に答える
5

SQL Server 2005 以降

CREATE TABLE dbo.Students
(
    StudentId INT
    , Name VARCHAR(50)
    , CONSTRAINT PK_Students PRIMARY KEY (StudentId)
);

CREATE TABLE dbo.Subjects
(
    SubjectId INT
    , Name VARCHAR(50)
    , CONSTRAINT PK_Subjects PRIMARY KEY (SubjectId)
);

CREATE TABLE dbo.Schedules
(
    StudentId INT
    , SubjectId INT
    , CONSTRAINT PK__Schedule PRIMARY KEY (StudentId, SubjectId)
    , CONSTRAINT FK_Schedule_Students FOREIGN KEY (StudentId) REFERENCES dbo.Students (StudentId)
    , CONSTRAINT FK_Schedule_Subjects FOREIGN KEY (SubjectId) REFERENCES dbo.Subjects (SubjectId)
);

INSERT dbo.Students (StudentId, Name) VALUES
    (1, 'Mary')
    , (2, 'John')
    , (3, 'Sam')
    , (4, 'Alaina')
    , (5, 'Edward')
;

INSERT dbo.Subjects (SubjectId, Name) VALUES
    (1, 'Physics')
    , (2, 'Geography')
    , (3, 'French')
    , (4, 'Gymnastics')
;

INSERT dbo.Schedules (StudentId, SubjectId) VALUES
    (1, 1)        --Mary, Physics
    , (2, 1)    --John, Physics
    , (3, 1)    --Sam, Physics
    , (4, 2)    --Alaina, Geography
    , (5, 2)    --Edward, Geography
;

SELECT
    sub.SubjectId
    , sub.Name AS [SubjectName]
    , ISNULL( x.Students, '') AS Students
FROM
    dbo.Subjects sub
    OUTER APPLY
    (
        SELECT
            CASE ROW_NUMBER() OVER (ORDER BY stu.Name) WHEN 1 THEN '' ELSE ', ' END
            + stu.Name
        FROM
            dbo.Students stu
            INNER JOIN dbo.Schedules sch
                ON stu.StudentId = sch.StudentId
        WHERE
            sch.SubjectId = sub.SubjectId
        ORDER BY
            stu.Name
        FOR XML PATH('')
    ) x (Students)
;
于 2016-06-01T20:42:40.670 に答える
4

私のリストには10​​項目未満しかなかったので、パフォーマンスの分析を行ったわけではありませんが、30個の奇妙な回答を調べた後、驚いたことに、単一のグループリストにCOALESCEを使用するのと同様に、すでに与えられた同様の回答にひねりがありました。 '変数を設定する必要さえありません(とにかくデフォルトはNULLです)。ソースデータテーブルのすべてのエントリが空白ではないことを前提としています:

DECLARE @MyList VARCHAR(1000), @Delimiter CHAR(2) = ', '
SELECT @MyList = CASE WHEN @MyList > '' THEN @MyList + @Delimiter ELSE '' END + FieldToConcatenate FROM MyData

COALESCE は内部的に同じ考えを使用していると確信しています。マイクロソフトが私にこれを変更しないことを願いましょう。

于 2016-06-10T02:03:25.653 に答える
3

SQL Serverでこれを行う1つの方法は、テーブルのコンテンツをXML(XML rawの場合)として返し、結果を文字列に変換してから、タグを "、"に置き換えることです。

于 2008-10-11T23:57:25.663 に答える
2
SELECT PageContent = Stuff(
    (   SELECT PageContent
        FROM dbo.InfoGuide
        WHERE CategoryId = @CategoryId
          AND SubCategoryId = @SubCategoryId
        for xml path(''), type
    ).value('.[1]','nvarchar(max)'),
    1, 1, '')
FROM dbo.InfoGuide info
于 2016-05-26T11:14:20.360 に答える
2

手遅れですが、すでに多くの解決策があります。MySQLの簡単なソリューションは次のとおりです。

SELECT t1.id,
        GROUP_CONCAT(t1.id) ids
 FROM table t1 JOIN table t2 ON (t1.id = t2.id)
 GROUP BY t1.id
于 2017-12-07T17:20:21.480 に答える
2

Oracle にはいくつかの方法があります。

    create table name
    (first_name varchar2(30));

    insert into name values ('Peter');
    insert into name values ('Paul');
    insert into name values ('Mary');

解決策は 1:

    select substr(max(sys_connect_by_path (first_name, ',')),2) from (select rownum r, first_name from name ) n start with r=1 connect by prior r+1=r
    o/p=> Peter,Paul,Mary

解決策は2です:

    select  rtrim(xmlagg (xmlelement (e, first_name || ',')).extract ('//text()'), ',') first_name from name
    o/p=> Peter,Paul,Mary
于 2012-09-28T20:44:47.400 に答える
1

これを使って:

ISNULL(SUBSTRING(REPLACE((select ',' FName as 'data()' from NameList for xml path('')), ' ,',', '), 2, 300), '') 'MyList'

「300」は、表示されると思われるアイテムの最大数を考慮して、任意の幅にすることができます。

于 2011-04-29T15:28:29.060 に答える
1

「TABLE」タイプを使用すると、非常に簡単です。テーブルが呼び出されStudents、 columnがあるとしますname

declare @rowsCount INT
declare @i INT = 1
declare @names varchar(max) = ''

DECLARE @MyTable TABLE
(
  Id int identity,
  Name varchar(500)
)
insert into @MyTable select name from Students
set @rowsCount = (select COUNT(Id) from @MyTable)

while @i < @rowsCount
begin
 set @names = @names + ', ' + (select name from @MyTable where Id = @i)
 set @i = @i + 1
end
select @names

この例は、 SQL Server 2008 R2でテストされています。

于 2013-12-02T09:25:52.907 に答える