查询逗号分隔的id到逗号分隔值

时间:2021-02-25 00:21:07

I have 2 tables

我有2张桌子

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.

我正在寻找像SQL查询一样的输出。

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?

我尝试了以下与depts连接,但只为每个dept生成一行。如何使用查询获得上述结果?

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

5 个解决方案

#1


6  

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('.[1]', 'nvarchar(max)'), 1, 1, '')
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.

但是,实际上,您应该规范化数据库。这绝对是一场噩梦。

#2


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.

好吧,你在这里问了很多问题。首先,要分割数据,你可以将其格式化为XML并使用CROSS APPLY - 技巧我看了一段时间后不需要内置函数。

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

这会将逗号分隔的字符串转换为字符串列表。然后,您可以使用FOR XML将它们重新组合在一起。

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.

这是SQL小提琴。

Good luck.

祝你好运。

#3


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:

您还可以使用递归CTE拆分数据,然后使用FOR XML PATH将行连接成一行:

;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

请参阅SQL Fiddle with Demo

Result:

结果:

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

#4


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:

您还可以使用带动态管理功能的选项sys.dm_fts_parser在脚本执行之前,您需要检查全文组件是否已安装:

SELECT FULLTEXTSERVICEPROPERTY ('IsFulltextInstalled')

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

0 =未安装全文。 1 =已安装全文。 NULL =无效输入或错误。

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

如果0 =未安装全文,那么这篇文章是必要的如何在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

#5


0  

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

编写用于拆分逗号分隔值的函数。我写了dbo.split

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

select * from dbo.split('1,2,3',',')将返回 - 数据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**

#1


6  

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('.[1]', 'nvarchar(max)'), 1, 1, '')
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.

但是,实际上,您应该规范化数据库。这绝对是一场噩梦。

#2


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.

好吧,你在这里问了很多问题。首先,要分割数据,你可以将其格式化为XML并使用CROSS APPLY - 技巧我看了一段时间后不需要内置函数。

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

这会将逗号分隔的字符串转换为字符串列表。然后,您可以使用FOR XML将它们重新组合在一起。

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.

这是SQL小提琴。

Good luck.

祝你好运。

#3


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:

您还可以使用递归CTE拆分数据,然后使用FOR XML PATH将行连接成一行:

;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

请参阅SQL Fiddle with Demo

Result:

结果:

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

#4


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:

您还可以使用带动态管理功能的选项sys.dm_fts_parser在脚本执行之前,您需要检查全文组件是否已安装:

SELECT FULLTEXTSERVICEPROPERTY ('IsFulltextInstalled')

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

0 =未安装全文。 1 =已安装全文。 NULL =无效输入或错误。

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

如果0 =未安装全文,那么这篇文章是必要的如何在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

#5


0  

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

编写用于拆分逗号分隔值的函数。我写了dbo.split

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

select * from dbo.split('1,2,3',',')将返回 - 数据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**