5

I have 2 tables

Departments

ID  Dept
---------
1   HR
2   Accts
3   IT

Employee

ID Name     Depts
-------------------
1  Kevin     2,1
2  Michelle  1
3  Troy      1,3
4  Rheesa    2,3,1

I am looking for an output like the following with a SQL query.

Employee depts

ID Name      Depts
-------------------------
 1 Kevin     Accts,HR
 2 Michelle  HR
 3 Troy      HR,IT
 4 Rheesa    Accts,IT,HR

I have tried the following that join s with depts but results in one row for each dept only. How do i get the above results using a query?

select 
    name, depts, dept 
from 
    employee
CROSS APPLY  
    dbo.split_list(employee.depts ,',') split
inner join 
    dbo.department on  depts= split.value
order by 
    name
1
  • 3
    I have no clue why everyone keeps trying to close your question (I even understood your previous question as poorly as it was worded -- I've seen a lot worse!). You have a valid issue -- you want to convert a comma delimited string to a list, query upon that list, and then convert the results back to a comma delimited result. Commented Jan 30, 2013 at 20:10

5 Answers 5

8
DECLARE @Departments TABLE 
(
  ID INT PRIMARY KEY, 
  Dept VARCHAR(32) NOT NULL UNIQUE
);

DECLARE @Employees TABLE
(
  ID INT PRIMARY KEY,
  Name NVARCHAR(64) NOT NULL,
  Depts VARCHAR(255) NOT NULL
);

INSERT @Departments VALUES 
  (1,'HR'),  (2,'Accts'),  (3,'IT');

INSERT @Employees VALUES
  (1,'Kevin','2,1'), (2,'Michelle','1'),
  (3,'Troy','1,3'),  (4,'Rheesa','2,3,1');

SELECT ID, Name, Depts = STUFF((SELECT ',' + d.Dept 
    FROM @Departments AS d
    INNER JOIN @Employees AS ei
    ON ',' + ei.Depts + ',' LIKE '%,' + CONVERT(VARCHAR(12), d.id) + ',%'
    WHERE ei.ID = e.ID
    ORDER BY Dept
    FOR XML PATH, 
    TYPE).value(N'/text().[1]', N'nvarchar(max)'), 1, 1, N'')
FROM @Employees AS e
ORDER BY ID;

The results don't quite match your required results, as the ordering is deterministic (ordered by department name):

ID      Name        Depts
----    --------    ----
1       Kevin       Accts,HR
2       Michelle    HR
3       Troy        HR,IT
4       Rheesa      Accts,HR,IT

If you want them ordered by the appearance in the comma-separated list, just change:

ORDER BY Dept

To:

ORDER BY CHARINDEX( ',' + CONVERT(VARCHAR(12), d.id) + ',', ',' + ei.Depts + ',')

Results:

ID      Name        Depts
----    --------    ----
1       Kevin       Accts,HR
2       Michelle    HR
3       Troy        HR,IT
4       Rheesa      Accts,IT,HR -- this is the only one affected as it turns out

However, in reality, you should normalize your database. This is an absolute nightmare.

Sign up to request clarification or add additional context in comments.

Comments

3

Looking beyond how you're storing your data, let me try to help you out.

Well, you're asking a lot of questions here. First, to split the data, you can format it as XML and use CROSS APPLY -- trick I saw a while back that didn't require built in functions.

That will convert your comma delimited string to a list of strings. You can then use FOR XML to put them back together.

Give this a shot:

SELECT
   E.Id, 
   E.Name, 
   STUFF(
        (
        SELECT ',' +  D.Department AS [text()]
        FROM  (
           SELECT A.[id],  
             Split.a.value('.', 'VARCHAR(100)') AS DeptId  
           FROM  
              (SELECT [id],  
                 CAST ('<M>' + REPLACE(Depts, ',', '</M><M>') + '</M>' AS XML) AS String  
              FROM  Employee
          ) AS A 
        CROSS APPLY String.nodes ('/M') AS Split(a)) A 
        JOIN Departments D ON A.DeptId = D.Id
        WHERE E.Id = A.Id
        FOR XML PATH('')
        ), 1, 1, '') AS Departments
FROM Employee E

And here is the SQL Fiddle.

Good luck.

Comments

2

You can also use a recursive CTE to split the data and then use FOR XML PATH to concatenate the rows into a single row:

;with cte (id, name, deptid, depts) as
(
  select id, name,
    cast(left(depts, charindex(',',depts+',')-1) as varchar(50)) deptid,
         stuff(depts, 1, charindex(',',depts+','), '') depts
  from employee
  union all
  select id, name,
    cast(left(depts, charindex(',',depts+',')-1) as varchar(50)) deptid,
    stuff(depts, 1, charindex(',',depts+','), '') depts
  from cte
  where depts > ''
) 
select e.id, e.name,
  stuff((
         select distinct ', '+ d.dept
         from cte c
         inner join departments d
            on c.deptid = d.id
         where e.id = c.id
         for XML path('')),1,1,'') Depts
from employee e

See SQL Fiddle with Demo

Result:

| ID |     NAME |          DEPTS |
----------------------------------
|  1 |    Kevin |      Accts, HR |
|  2 | Michelle |             HR |
|  3 |     Troy |         HR, IT |
|  4 |   Rheesa |  Accts, HR, IT |

Comments

1

Also you can use option with dynamic management function sys.dm_fts_parser
Before script execution you need check full-text component is installed:

SELECT FULLTEXTSERVICEPROPERTY ('IsFulltextInstalled')

0 = Full-text is not installed. 1 = Full-text is installed. NULL = Invalid input, or error.

If 0 = Full-text is not installed then this post is necessary to you How to install fulltext on sql server 2008?

SELECT b.ID, b.Name, STUFF((
SELECT ',' + d.Dept
FROM Employees e 
  JOIN Departments d ON d.ID IN(
                                SELECT display_term 
                                FROM sys.dm_fts_parser('"' + e.Depts + '"', 1033, NULL, 0) 
                                WHERE display_term NOT LIKE 'nn%'
                                )
WHERE b.ID = e.ID
ORDER BY d.Dept
FOR XML PATH('')), 1, 1, '') AS Depts
FROM Employees b

OR

SELECT e.ID, e.Name, 
 (
  STUFF((
  SELECT ',' + Dept
  FROM sys.dm_fts_parser('"' + e.Depts + '"', 1033, NULL, 0) p JOIN Departments d ON p.display_term = d.ID
  WHERE display_term NOT LIKE 'nn%'
  FOR XML PATH('')), 1, 1, '')
  ) AS Depts
 FROM Employees e

Comments

0

Write a function for splitting comma separated values. I wrote dbo.split

select * from dbo.split('1,2,3',',') Will return as - Data 1 2 3

SELECT tact.ActivityID,CONVERT(NVARCHAR(20),tact.createddate,103) AS CallDate,
ActivityOriginatedByPartyID , (ISNULL(p.firstname,'')+' '+ISNULL(p.lastname,'')) AS PartnerName,
u.UserName AS PSTName, ccv.codevalue AS CallType
**, ccv1.codevalue AS CallContext**
,tact.ActivityNote AS CallTrackerNote,
(CONVERT(VARCHAR(20),tact.ActivityTimeSpend) + ' Min') AS CallDuration
FROM txn_activity tact (NOLOCK)
INNER JOIN TXN_Party p (NOLOCK) ON p.PartyID = tact.ActivityOriginatedByPartyID 
INNER JOIN TXN_User u (NOLOCK) ON u.userid = tact.createdby
INNER JOIN CFG_CodeValue ccv (NOLOCK) ON ccv.codevalueid = tact.ActivityTypeID
--INNER JOIN CFG_CodeValue ccv1 (NOLOCK) ON ccv1.codevalueid = tact.ActivityContext

**CROSS APPLY  
    dbo.split(tact.ActivityContext,',') split
inner join 
    dbo.CFG_CodeValue ccv1 (NOLOCK) ON ccv1.codevalueid = split.data**

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.