Reputation: 23
I've got a table Employees with employees (say the important fields are ID int, Name varchar(50)) and a table Areas with sales areas (ID int, EmployeeID int, USState char(2)).
The sample values are:
Employees
ID Name
1 Shoeman
2 Smith
3 Johnson
Areas
ID EmployeeID USState
1 1 NY
2 1 FL
3 1 AR
4 2 DC
5 2 AR
6 3 TX
Can anyone give me a hint on making a SQL query to get the output recordset in the following way:
EmployeeID USState
1 NY FL AR
2 DC AR
3 TX
Target platform: SQL Server 2005.
Upvotes: 2
Views: 487
Reputation: 11
This is my perfered format to use a UDF (appears to be much faster as well on a large DB)
CREATEFUNCTION dbo.StateList(@ID int) RETURNS varchar(max)
AS
DECLARE @out varchar(max);
SET @out=''; -- comment this out to reutrn NULL if nothing found
SELECT @out=@out+USState+' ' -- operates like a loop assigning the values in sequence to the out variable.
FROM AREAS
WHERE EmployeeID=@ID
ORDER BY USState
RETURN @out
Query example ...
SELECT Name, dbo.StateList(EmployeeID)
FROM Employees
Order BY Name
In this manner you create one UDF for each list you wish to explode in this way.
Upvotes: 1
Reputation: 838336
This operation is called GROUP_CONCAT in MySQL but SQL Server doesn't support it.
In SQL Server you can simulate the same functionality using the FOR XML PATH hack.
SELECT extern.EmployeeID, states AS USState
FROM Areas AS extern
CROSS APPLY (
SELECT USState + ' '
FROM Areas AS intern
WHERE extern.EmployeeID = intern.EmployeeID
FOR XML PATH('')
) T1 (states)
GROUP BY extern.EmployeeID, states
ORDER BY extern.EmployeeID
An alternative is to use a recursive CTE. This is a less hacky solution but it is also more complicated:
WITH qs(EmployeeID, USState, rn, cnt) AS
(
SELECT
EmployeeID,
USState,
ROW_NUMBER() OVER (PARTITION BY EmployeeID ORDER BY USState),
COUNT(*) OVER (PARTITION BY EmployeeID)
FROM Areas
),
t (EmployeeID, prodname, gc, rn, cnt) AS
(
SELECT EmployeeID, USState, CAST(USState AS NVARCHAR(MAX)), rn, cnt
FROM qs
WHERE rn = 1
UNION ALL
SELECT
qs.EmployeeID, qs.USState,
CAST(t.gc + ' ' + qs.USState AS NVARCHAR(MAX)),
qs.rn, qs.cnt
FROM t
JOIN qs ON qs.EmployeeID = t.EmployeeID
AND qs.rn = t.rn + 1
)
SELECT EmployeeID, gc AS USState
FROM t
WHERE rn = cnt
ORDER BY EmployeeID
OPTION (MAXRECURSION 0)
Both methods give the result you want:
EmployeeID USState 1 NY FL AR 2 DC AR 3 TX
Upvotes: 2