Вот один из способов сделать это без функции разделения и без цикла.Обратите внимание, что это не получается в точном порядке ожидаемого результата.
DECLARE @pos TABLE
(
PositionId INT,
PositionName VARCHAR(32)
);
INSERT @pos SELECT 1, 'Defensive End'
UNION ALL SELECT 2, 'Quarterback'
UNION ALL SELECT 3, 'Pitcher'
UNION ALL SELECT 4, 'Catcher'
UNION ALL SELECT 5, 'First Base';
DECLARE @row TABLE(pList VARCHAR(32));
INSERT @row SELECT '1,2,3,'
UNION ALL SELECT '1,0,0,'
UNION ALL SELECT '0,0,0,';
;WITH cte AS
(
SELECT x.pList, p.PositionName
FROM @row AS x LEFT OUTER JOIN @pos AS p
ON ',' + x.pList LIKE '%,' + CONVERT(VARCHAR(12), p.PositionID) + ',%'
)
SELECT COALESCE(NULLIF(STUFF((
SELECT ', ' + PositionName
FROM cte AS cte2 WHERE cte.pList = cte2.pList
FOR XML PATH(''), TYPE).value('.[1]','varchar(max)'), 1, 2, ''), ''),
'No position selected'
)
FROM cte
GROUP BY pList;
РЕДАКТИРОВАТЬ
Вот немного другая версия, которая, кажется, подчиняетсяпорядок в исходном списке и опирается на таблицу чисел ...
CREATE TABLE dbo.Numbers(n INT PRIMARY KEY);
INSERT dbo.Numbers(n) SELECT TOP 1000 ROW_NUMBER() OVER
(ORDER BY s1.[object_id]) FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2;
... и подсказку OPTION (FORCE ORDER)
:
;WITH cte AS
(
SELECT *, r = ROW_NUMBER() OVER (PARTITION BY pList ORDER BY n.n)
FROM @row AS r LEFT OUTER JOIN @pos AS p
ON ',' + r.pList + ',' LIKE '%,' + RTRIM(p.PositionId) + ',%'
LEFT OUTER JOIN dbo.Numbers AS n
ON n.n = CHARINDEX(',' + RTRIM(p.PositionId) + ',', ',' + r.pList + ',')
)
SELECT DISTINCT pList, Position = COALESCE(STUFF((SELECT ',' + PositionName
FROM cte AS cte2 INNER JOIN dbo.Numbers AS n ON n.n = cte2.r
WHERE cte2.pList = cte.pList FOR XML PATH(''), TYPE
).value('.[1]', 'nvarchar(max)'), 1, 1, ''), 'No position selected')
FROM cte OPTION (FORCE ORDER);
Это основывается на предположении, что оптимизаторвыберет кластерный первичный ключ в таблице номеров.Для дальнейшего применения этого может иметь смысл убедиться, что этот индекс используется, присвоив ему имя с помощью подсказки WITH (INDEX)
в обоих соединениях к dbo.Numbers
(что означает, что вы, вероятно, должны назвать ограничение первичного ключа, а не делать его ленивым).как я делал выше).
Извините, мне понадобилось немного времени, чтобы вернуться к этому.