web-dev-qa-db-ja.com

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

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

Peter
Paul
Mary

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

1687
JohnnyM

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

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
1247
Ritesh

この回答は返すかもしれません 予期しない結果 一貫した結果を得るために、他の回答で説明されているFOR XML PATHメソッドのいずれかを使用してください。

COALESCEを使う:

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

ちょっと説明してください(この回答は比較的定期的な見解を得るように思われるので):

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

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

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

  • 上記の解決策は、行にNULL Name値がある場合、誤った結果をもたらします(NULLがある場合、NULLはその行の後に@NamesNULLを入力すると、次の行は再び空の文字列として始まります。
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 sを除外し、2番目のオプションはそれらをマーカーメッセージでリストに残します。 。

945
Chris Shaffer

MS SQL ServerのXMLdata()コマンドでまだ表示されていない方法の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
332
jens frandsen

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;
282
Mathieu Renda

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   [email protected]
2   NULL
3   [email protected], [email protected]

データに無効なXML文字が含まれていてもこれは機能します。

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

', 'は任意の文字列の区切り文字に置き換えることができます


そしてSQL Server 2017では、Azure SQL Database

新しい STRING_AGG関数を使用することができます

266
Steven Chong

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
111
Darryl Hein

COALESCE - こちらから詳細を見る

例:

102

103

104

その後、SQL Serverで以下のコードを書く。

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
54
pedram

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以降は さらに簡単になりました です。

47
hgmnz

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

45
Alex

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
33

私は自宅でSQL Serverにアクセスできないので、ここの構文を推測しますが、それは多かれ少なかれです:

DECLARE @names VARCHAR(500)

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

最終結果を保持して選択する変数を作成する必要があります。

最も簡単な解決策

DECLARE @char VARCHAR(MAX);

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

PRINT @char;
25
Tigerjz32

再帰的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
24
jmoreno

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

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

Hgmnzで示されるように9.0より前のバージョンではarray_agg()を使うことができます

23

SQL Server vNextでは、これはSTRING_AGG関数を使用して構築されます。詳細については、こちらを参照してください。 https://msdn.Microsoft.com/ja-jp/library/mt790580.aspx

21
Henrik Fransas

追加のコンマなしですぐに使えるソリューション:

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

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

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

17
Daniel Reis

XMLを使用すると、行をコンマで区切ることができました。余分なカンマのために私達はSQL Serverのreplace機能を使うことができます。コンマを追加する代わりに、AS 'data()'を使用すると、行がスペースで連結されます。スペースは、後で説明する構文のように後でコンマに置き換えることができます。

REPLACE(
        (select FName AS 'data()'  from NameList  for xml path(''))
         , ' ', ', ') 
17
Diwakar
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
12
Max Szczurek
DECLARE @Names VARCHAR(8000)
SELECT @name = ''
SELECT @Names = @Names + ',' + Names FROM People
SELECT SUBSTRING(2, @Names, 7998)

これは、浮遊コンマを始めに入れます。

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

XML句をSELECT句の中で相関副照会として使用することもできます(ただし、Googleは自宅で仕事をしていないため、仕事に戻るまで待たなければなりません:-)

10
gbn

他の答えと一緒に、答えを読む人は車や学生のような特定のドメインテーブルを知っていなければなりません。ソリューションをテストするには、テーブルを作成してデータを入力する必要があります。

以下は、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 

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

最善の答えは、Oracle 11g Release 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()関数もオプションです。これは安定しているように見えますが、どのアプリケーションSQLにも使用しないことを明示的に推奨していますので、ご自身の責任で使用してください。

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

7
ZeroK

Dana's answer の優雅さがとても気に入りました。それを完成させたいだけでした。

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

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

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

NULL値を避けるためには、CONCAT()を使用できます。

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

この答えは動作するためにサーバーの特権を必要とします。

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

あなたが望むなら、私はすでにアセンブリを作成しています、そしてそれは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

Assemblyへのパスがサーバーからアクセス可能である可能性があることに注意してください。これですべてのステップが正常に完了したので、次のような機能を使用することができます。

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

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

6
Nizam

私は通常SQL Serverで文字列を連結するのにこのようにselectを使います:

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

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
user1767754

Nullを扱う場合は、where句を追加するか、最初の句の周囲に別のCOALESCEを追加することで実現できます。

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

これも役に立ちます

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
4
endo64

Oracleでは、wm_concatです。この機能は 10gリリース 以降で利用可能だと思います。

4
user762952

このメソッドは、そのNPATH機能を利用する場合に限り、Teradata Asterデータベースに適用されます。

また、テーブルStudentsがあります。

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

NPATHではそれは単なるSELECTです:

SELECT * FROM npath(
  ON Students
  PARTITION BY SubjectID
  ORDER BY StudentName
  MODE(nonoverlapping)
  PATTERN('A*')
  SYMBOLS(
    'true' as A
  )
  RESULT(
    FIRST(SubjectID of A) as SubjectID,
    ACCUMULATE(StudentName of A) as StudentName
  )
);

結果:

SubjectID       StudentName
----------      -------------
1               [John, Mary, Sam]
2               [Alaina, Edward]
3
topchef

私のリストは10項目に満たなかったのでパフォーマンスの分析をしたわけではありませんが、30個の奇妙な答えを見て驚きました。私の変数を設定する必要さえありません(とにかくデフォルトはNULLです)、そしてそれは私のソースデータテーブルの全てのエントリが空白でないと仮定します:

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

私はCOALESCEが内部的に同じ考えを使っていると確信しています。 MSがこれを変更しないようにしてください。

3
Glen

これを達成するための完全な解決策は次のとおりです。

-- Table Creation
CREATE TABLE Tbl
( CustomerCode    VARCHAR(50)
, CustomerName    VARCHAR(50)
, Type VARCHAR(50)
,Items    VARCHAR(50)
)

insert into Tbl
SELECT 'C0001','Thomas','BREAKFAST','Milk'
union SELECT 'C0001','Thomas','BREAKFAST','Bread'
union SELECT 'C0001','Thomas','BREAKFAST','Egg'
union SELECT 'C0001','Thomas','LUNCH','Rice'
union SELECT 'C0001','Thomas','LUNCH','Fish Curry'
union SELECT 'C0001','Thomas','LUNCH','Lessy'
union SELECT 'C0002','JOSEPH','BREAKFAST','Bread'
union SELECT 'C0002','JOSEPH','BREAKFAST','Jam'
union SELECT 'C0002','JOSEPH','BREAKFAST','Tea'
union SELECT 'C0002','JOSEPH','Supper','Tea'
union SELECT 'C0002','JOSEPH','Brunch','Roti'

-- function creation
GO
CREATE  FUNCTION [dbo].[fn_GetItemsByType]
(   
    @CustomerCode VARCHAR(50)
    ,@Type VARCHAR(50)
)
RETURNS @ItemType TABLE  ( Items VARCHAR(5000) )
AS
BEGIN

        INSERT INTO @ItemType(Items)
    SELECT  STUFF((SELECT distinct ',' + [Items]
         FROM Tbl 
         WHERE CustomerCode = @CustomerCode
            AND Type=@Type
            FOR XML PATH(''))
        ,1,1,'') as  Items



    RETURN 
END

GO

-- fianl Query
DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(Type) 
                    from Tbl
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT CustomerCode,CustomerName,' + @cols + '
             from 
             (
                select  
                    distinct CustomerCode
                    ,CustomerName
                    ,Type
                    ,F.Items
                    FROM Tbl T
                    CROSS APPLY [fn_GetItemsByType] (T.CustomerCode,T.Type) F
            ) x
            pivot 
            (
                max(Items)
                for Type in (' + @cols + ')
            ) p '

execute(@query) 
3
Ravi Pipaliya

- 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)
;
3
Graeme

これはどう:

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

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

2
Hans Bluh

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

2
Manu

@ User1460901このようなことを試すことができます。

WITH cte_base AS (
    SELECT CustomerCode, CustomerName,
    CASE WHEN Typez = 'Breakfast' THEN Items ELSE NULL END AS 'BREAKFAST'
    , CASE WHEN Typez = 'Lunch' THEN Items ELSE NULL END AS 'LUNCH'
    FROM #Customer
    )
    SELECT distinct CustomerCode, CustomerName,
    SUBSTRING(
    (   
        SELECT ','+BREAKFAST AS [text()]
        FROM cte_base b1
        WHERE b1.CustomerCode = b2.CustomerCode AND b1.CustomerName = b2.CustomerName
        ORDER BY b1.BREAKFAST
        FOR XML PATH('')
        ), 2, 1000
    ) [BREAKFAST], 
    SUBSTRING(
    (   
        SELECT ','+LUNCH AS [text()]
        FROM cte_base b1
        WHERE b1.CustomerCode = b2.CustomerCode AND b1.CustomerName = b2.CustomerName
        ORDER BY b1.LUNCH
        FOR XML PATH('')
        ), 2, 1000
    ) [LUNCH]
    FROM cte_base b2
1
Aura
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
1
Muhammad Bilal

次に示すのは、「basic loop」と「rownum」を使用して特定のシナリオを実装するための簡単なPL/SQLプロシージャです。

テーブル定義

CREATE TABLE "NAMES" ("NAME" VARCHAR2(10 BYTE))) ;

この表に値を挿入しましょう

INSERT INTO NAMES VALUES('PETER');
INSERT INTO NAMES VALUES('PAUL');
INSERT INTO NAMES VALUES('MARY');

手続きはここから始まります

DECLARE 

MAXNUM INTEGER;
CNTR INTEGER := 1;
C_NAME NAMES.NAME%TYPE;
NSTR VARCHAR2(50);

BEGIN

SELECT MAX(ROWNUM) INTO MAXNUM FROM NAMES;

LOOP

SELECT NAME INTO  C_NAME FROM 
(SELECT ROWNUM RW, NAME FROM NAMES ) P WHERE P.RW = CNTR;

NSTR := NSTR ||','||C_NAME;
CNTR := CNTR + 1;
EXIT WHEN CNTR > MAXNUM;

END LOOP;

dbms_output.put_line(SUBSTR(NSTR,2));

END;

結果

PETER,PAUL,MARY
1
Pooja Bhat

TABLE型ではとても簡単です。あなたのテーブルがStudentsと呼ばれ、それにカラム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

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

1
Max Tkachenko

手遅れですが、すでに多くの解決策があります。これがMySQLのための簡単な解決策です:

SELECT t1.id,
        GROUP_CONCAT(t1.id) ids
 FROM table t1 JOIN table t2 ON (t1.id = t2.id)
 GROUP BY t1.id
1
Shahbaz

再帰的なクエリでそれをすることができます:

-- Create example table
CREATE TABLE tmptable (NAME VARCHAR(30)) ;

-- Insert example data
INSERT INTO tmptable VALUES('PETER');
INSERT INTO tmptable VALUES('PAUL');
INSERT INTO tmptable VALUES('MARY');

-- Recurse query
with tblwithrank as (
select * , row_number() over(order by name) rang , count(*) over() NbRow
from tmptable
),
tmpRecursive as (
select *, cast(name as varchar(2000)) as AllName from tblwithrank  where rang=1
union all
select f0.*,  cast(f0.name + ',' + f1.AllName as varchar(2000)) as AllName 
from tblwithrank f0 inner join tmpRecursive f1 on f0.rang=f1.rang +1 
)
select AllName from tmpRecursive
where rang=NbRow
1
Esperento57

Oracleにはさらに2つの方法があります。

    create table name
    (first_name varchar2(30));

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

    Solution 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

    Soution 2:
    select  rtrim(xmlagg (xmlelement (e, first_name || ',')).extract ('//text()'), ',') first_name from name
    o/p=> Peter,Paul,Mary

次のように、RECUSRSIVITY、WITH CTE、UNION ALLを使用できます。

declare @mytable as table(id int identity(1,1), str nvarchar(100))
insert into @mytable values('Peter'),('Paul'),('Mary')

declare @myresult as table(id int,str nvarchar(max),ind int, R# int)

;with cte as(select id,cast(str as nvarchar(100)) as str, cast(0 as int) ind from @mytable
union all
select t2.id,cast(t1.str+',' +t2.str as nvarchar(100)) ,t1.ind+1 from cte t1 inner join @mytable t2 on t2.id=t1.id+1)
insert into @myresult select *,row_number() over(order by ind) R# from cte

select top 1 str from @myresult order by R# desc
0
Kemal AL GAZZAH

クリス・シャファーの答えの上に

データが繰り返される可能性がある場合

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
0
asmgx