読者です 読者をやめる 読者になる 読者になる

SQL Server で文字列を全部結合したいだけなら

SQL

以下のように記述すれば出来るっぽい。

DECLARE @str AS varchar(max);
SET @str = '';
SELECT @str = @str + str FROM SomeTable;
SELECT @str;

参考:文字列を集計的に結合する(ユーザー定義関数経由で GROUP BY 対応)
カンマ区切りがしたければ、

DECLARE @str AS varchar(max);
SET @str = '';
SELECT
    -- 先頭要素にはカンマを付けない
    @str = CASE @str
             WHEN '' THEN str
                     ELSE @str + ', ' + str
           END
FROM
    SomeTable
;
SELECT @str;

とか。

でも

これはあくまで対象全部を結合するのであって、例えば、

n str
1 hoge
1 piyo
2 foo
2 bar

みたいなテーブルを、

n strs
1 hoge, piyo
2 foo, bar

のように GROUP BY することは出来ない*1
SomeTable が n 順にソートされてることが前提で、

DECLARE @str AS varchar(max);
SET @str = '';
DECLARE @n AS int;
-- ありえない数値を入れておく
SET @n = -1;
SELECT
    -- nが変わるタイミングで@strをリセット
    @str = CASE @n
             WHEN n THEN @str
                    ELSE ''
           END
  , @str = CASE @str
             WHEN '' THEN str
                     ELSE @str + ', ' + str
           END
     -- @nの更新
   , @n = n
FROM
    SomeTable
;
SELECT @n, @str;

こうすれば、

n str
2 foo, bar

は出せる*2し、@str には途中、「hoge, piyo」も入るから、あと何ひねりかすれば出来るのかもしれない。
つか、T-SQL 独自の機能使ってるんだから、これでいいじゃん、とか思わなくも無いけどね。

-- 結果格納用のテーブル変数
DECLARE @Strs AS TABLE(n int, str varchar(max));

-- nの個数
DECLARE @count AS int;
SELECT @count = COUNT(DISTINCT n) FROM SomeTable;

DECLARE @i AS int;
SET @i = 0;
WHILE @i < @count BEGIN
  DECLARE @str AS varchar(max);
  SET @str = '';
  
  -- nが@i + 1の文字列を結合
  SELECT
      @str = CASE @str
               WHEN '' THEN str
                       ELSE @str + ', ' + str
             END
  FROM
      SomeTable
  WHERE
      n = @i + 1
  ;
  
  -- @i + 1と共に結合した文字列を格納
  INSERT INTO @Strs VALUES(@i + 1, @str);
  
  SET @i = @i + 1;
END

-- 全部出力
SELECT * FROM @Strs;

n が 1 から連続してない場合、

DECLARE @Strs AS TABLE(n int, str varchar(max));
-- 連番とnの対応表
DECLARE @Ns AS TABLE(i int identity(0, 1), n int);

DECLARE @count AS int;
SELECT @count = COUNT(DISTINCT n) FROM SomeTable;

-- iは自動採番して、nはSomeTableから取ってくる
INSERT INTO @Ns(n)
  SELECT DISTINCT n FROM SomeTable
;

DECLARE @i AS int;
SET @i = 0;
WHILE @i < @count BEGIN
  -- @iに対応するnを格納
  DECLARE @n AS int;
  SELECT @n = n FROM @Ns WHERE i = @i;
  
  DECLARE @str AS varchar(max);
  SET @str = '';
  SELECT
      @str = CASE @str
               WHEN '' THEN str
                       ELSE @str + ', ' + str
             END
  FROM
      SomeTable
  WHERE
      n = @n
  ;
  INSERT INTO @Strs VALUES(@n, @str);
  SET @i = @i + 1;
END

SELECT * FROM @Strs;

CLR ユーザー定義集計関数なんてものもあるみたいだけど、正直、おおげさすぎるというかなんと言うか・・・


でもやっぱり FOLD 欲しい

*1:さっきのページではユーザ定義関数で実現してる

*2:ただ、SELECT 句が前から順に評価されるってのが保証されてるかどうか不明