Este podría ser el enfoque más limpio que buscas. Básicamente, verifique si la variable ya se ha inicializado. Si no es así, configúrelo en la cadena vacía y agregue la primera ciudad (sin comas iniciales). Si es así, entonces agregue una coma, luego agregue la ciudad.
DECLARE @col nvarchar(MAX);
SELECT @col = COALESCE(@col + ',', '') + city
FROM dbo.tbl WHERE state = 'California';
Por supuesto, eso solo funciona para llenar una variable por estado. Si está sacando la lista para cada estado, uno a la vez, hay una mejor solución de una vez:
SELECT [state], cities = STUFF((
SELECT N', ' + city FROM dbo.tbl
WHERE [state] = x.[state]
FOR XML PATH(''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 2, N'')
FROM dbo.tbl AS x
GROUP BY [state]
ORDER BY [state];
Resultados:
state cities
---------- --------------------------------------
California San Francisco, Los Angeles, Sacramento
Florida Miami, Jacksonville
Para ordenar por nombre de ciudad dentro de cada estado:
SELECT [state], cities = STUFF((
SELECT N', ' + city FROM dbo.tbl
WHERE [state] = x.[state]
ORDER BY city
FOR XML PATH(''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 2, N'')
FROM dbo.tbl AS x
GROUP BY [state]
ORDER BY [state];
En Azure SQL Database o SQL Server 2017+, puede usar la nueva STRING_AGG()
función :
SELECT [state], cities = STRING_AGG(city, N', ')
FROM dbo.tbl
GROUP BY [state]
ORDER BY [state];
Y ordenado por nombre de ciudad:
SELECT [state], cities = STRING_AGG(city, N', ')
WITHIN GROUP (ORDER BY city)
FROM dbo.tbl
GROUP BY [state]
ORDER BY [state];