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
请参阅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
请参阅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**