Для чистого и эффективного решения вы можете создать определяемая пользователем агрегатная функция , есть даже пример , который делает именно то, что вам нужно.
Затем вы можете использовать его, как любую другую агрегатную функцию (со стандартным планом запроса):
Это будет делать:
SELECT mt.ID,
SUBSTRING((SELECT mt2.Value
FROM MyTable AS mt2
WHERE mt2.ID = mt.ID
ORDER BY mt2.VALUE
FOR XML PATH('')), 3, 2000) AS JoinedValue
FROM MyTable AS mt
Это просто пришло мне в голову как одно из возможных решений. Не имею представления о производительности, но подумал, что это будет интересный способ решить проблему. Я проверил, что это работает в простой ситуации (я не кодировал для учета NULL). Не стесняйтесь дать ему тест, чтобы увидеть, хорошо ли он работает для вас.
Таблица, которую я использовал, включала идентификатор (my_id). Это может быть любой столбец, который уникален в группе (grp_id), так что это может быть столбец даты или что-то еще.
;WITH CTE AS (
SELECT
T1.my_id,
T1.grp_id,
CAST(T1.my_str AS VARCHAR) AS my_str
FROM
dbo.Test_Group_Concat T1
WHERE NOT EXISTS (SELECT * FROM dbo.Test_Group_Concat T2 WHERE T2.grp_id = T1.grp_id AND T2.my_id < T1.my_id)
UNION ALL
SELECT
T3.my_id,
T3.grp_id,
CAST(CTE.my_str + T3.my_str AS VARCHAR)
FROM
CTE
INNER JOIN dbo.Test_Group_Concat T3 ON
T3.grp_id = CTE.grp_id AND
T3.my_id > CTE.my_id
WHERE
NOT EXISTS (SELECT * FROM dbo.Test_Group_Concat T4 WHERE
T4.grp_id = CTE.grp_id AND
T4.my_id > CTE.my_id AND
T4.my_id < T3.my_id)
)
SELECT
CTE.grp_id,
CTE.my_str
FROM
CTE
INNER JOIN (SELECT grp_id, MAX(my_id) AS my_id FROM CTE GROUP BY grp_id) SQ ON
SQ.grp_id = CTE.grp_id AND
SQ.my_id = CTE.my_id
ORDER BY
CTE.grp_id
Часто здесь задают .
Наиболее эффективный способ - использовать трюк FOR XML PATH.