Sql server SQL Server 2016 T-SQL将逗号字符串转换为内部联接数据库名称
我有一个列的值,如下所示:Sql server SQL Server 2016 T-SQL将逗号字符串转换为内部联接数据库名称,sql-server,tsql,sql-server-2016,Sql Server,Tsql,Sql Server 2016,我有一个列的值,如下所示: ID | userPerms | Name | DOB -----+-----------+-----------+---------- 5985 |1,3,4 |Bob Barker |12/12/1923 895 |1,2 |Bill Gates |10/14/1955 5897 |1,2,4 |Steve Jobs |02/24/1955 SET DATEFORMAT mdy; DECLARE @tblDat
ID | userPerms | Name | DOB
-----+-----------+-----------+----------
5985 |1,3,4 |Bob Barker |12/12/1923
895 |1,2 |Bill Gates |10/14/1955
5897 |1,2,4 |Steve Jobs |02/24/1955
SET DATEFORMAT mdy;
DECLARE @tblData TABLE(ID INT, userPerms VARCHAR(100),Name VARCHAR(100),DOB DATE);
INSERT INTO @tblData VALUES
(5985,'1,3,4','Bob Barker','12/12/1923')
,(895,'1,2','Bill Gates','10/14/1955')
,(5897,'1,2,4','Steve Jobs','02/24/1955');
DECLARE @tblPerm TABLE(ID INT, Perm VARCHAR(100));
INSERT INTO @tblPerm VALUES
(1,'Read')
,(2,'Write')
,(3,'Upload')
,(4,'Admin');
SELECT d.ID,d.Name,d.DOB
,STRING_AGG(p.Perm,',') AS Perms
FROM @tblData AS d
CROSS APPLY STRING_SPLIT(d.userPerms,',') AS A
INNER JOIN @tblPerm AS p ON CAST(A.value AS INT)=p.ID --<-- added cast to int
GROUP BY d.ID,d.Name,d.DOB;
该列是userPerms列
我需要能够内部连接与这些数字相关联的userPerm表
我的查询当前为:
SELECT
uT.employeeID + '|' + uT.lastFirstMiddle + '|' + uT.ntName + '|' + uT.email + '|' +
uT.firstName + '|' + uT.lastName + '|' + uT.active + '|' + uT.userPerms + '|' +
uT.userPermPages
FROM
usersTbl AS uT
INNER JOIN
usersPermissions AS uP ON uP.id = uT.userPerms
WHERE
uT.id = 1
当然,它不会工作,因为数据中有逗号
因此,我在输出中寻找的是:
ID | userPerms | Name | DOB
-----+------------------+-----------+------------
5985 |Read,Upload,Admin |Bob Barker |12/12/1923
895 |Read,Write |Bill Gates |10/14/1955
5897 |Read,Write,Admin |Steve Jobs |02/24/1955
有没有人知道如何将它们分开,以便内部连接按设计工作
更新1
我让它工作了,但是:
它不会将userperm组合到原始字符串中
SELECT
uT.employeeID + '|' + uT.lastFirstMiddle + '|' + uT.ntName + '|' +
uT.email + '|' + uT.firstName + '|' + uT.lastName + '|' + uT.active,
(
SELECT
',' + uP.type
FROM
usersPermissions AS uP
WHERE
',' + uT.userPerms + ','
LIKE
'%,' + cast(uP.id AS nvarchar(20)) + ',%'
FOR
XML PATH(''), TYPE
).value('substring(text()[1], 2)', 'varchar(max)') AS userPerms,
(
SELECT
',' + uP.name
FROM
pagePermissions AS uP
WHERE
',' + uT.userPerms + ','
LIKE
'%,' + cast(uP.id AS nvarchar(20)) + ',%'
FOR
XML PATH(''), TYPE
).value('substring(text()[1], 2)', 'varchar(max)') AS userPermPages
FROM
usersTbl as uT
WHERE
uT.id = '1';
对于这样的ID列表,DB设计不是很好。最好使用关系表来存储多对多关系。也就是说,这可能会奏效:
我们的想法是在uT.userPerms的开头和结尾添加逗号,并使用like运算符连接到uP.id的任何出现,在uT.userPerms中也用逗号包围。好吧,你问我……:- 我目前没有安装SQL Server 2016,因此这是未经测试的air代码。但我认为你需要这样的东西:
ID | userPerms | Name | DOB
-----+-----------+-----------+----------
5985 |1,3,4 |Bob Barker |12/12/1923
895 |1,2 |Bill Gates |10/14/1955
5897 |1,2,4 |Steve Jobs |02/24/1955
SET DATEFORMAT mdy;
DECLARE @tblData TABLE(ID INT, userPerms VARCHAR(100),Name VARCHAR(100),DOB DATE);
INSERT INTO @tblData VALUES
(5985,'1,3,4','Bob Barker','12/12/1923')
,(895,'1,2','Bill Gates','10/14/1955')
,(5897,'1,2,4','Steve Jobs','02/24/1955');
DECLARE @tblPerm TABLE(ID INT, Perm VARCHAR(100));
INSERT INTO @tblPerm VALUES
(1,'Read')
,(2,'Write')
,(3,'Upload')
,(4,'Admin');
SELECT d.ID,d.Name,d.DOB
,STRING_AGG(p.Perm,',') AS Perms
FROM @tblData AS d
CROSS APPLY STRING_SPLIT(d.userPerms,',') AS A
INNER JOIN @tblPerm AS p ON CAST(A.value AS INT)=p.ID --<-- added cast to int
GROUP BY d.ID,d.Name,d.DOB;
将拆分函数与交叉应用一起使用如何?然后将结果转换为CSV?有没有可能修复数据结构?存储带分隔符的数据违反了1NF的规定,并且会造成令人难以置信的痛苦。实际上,这种事情应该由角色来处理,而不是由每个用户来处理。将权限分配给角色,然后将用户分配给角色。SQL Server 2016提供STRING_SPLIT和STRING_AGG。使用第一个和CROSS APPLY将您的ID作为派生表,然后使用连接绑定您的值,最后使用第二个重新关联结果。@danihp真的!Codd将varchar值“%”、“+uT.userPerms+”、“like%”、“+castuP.id as nvarchar20+”、“%”转换为数据类型int时,保存quee…ry.-d转换失败,但仍然显示数字。“STRING_AGG”不是可识别的内置函数名。@StealthRT是否确实在SQL Server 2016上运行,目标数据库是否处于适当的兼容性级别,SSM是否为合适的版本?无法测试它。。。阅读MSDN中的两个函数。如果您无法使这些功能正常工作,有几种方法可以替换这些功能。
create table #tblData (ID INT, userPerms VARCHAR(100),Name VARCHAR(100),DOB DATE);
INSERT INTO #tbldata VALUES
(5985,'1,3,4','Bob Barker','12/12/1923')
,(895,'1,2','Bill Gates','10/14/1955')
,(5897,'1,2,4','Steve Jobs','02/24/1955');
create table #tblPerm (ID INT, Perm VARCHAR(100));
INSERT INTO #tblPerm VALUES
(1,'Read')
,(2,'Write')
,(3,'Upload')
,(4,'Admin');
Create FUNCTION [dbo].[fnSplitString]
(
@string NVARCHAR(MAX),
@delimiter CHAR(1)
)
RETURNS @output TABLE(splitdata NVARCHAR(MAX)
)
BEGIN
DECLARE @start INT, @end INT
SELECT @start = 1, @end = CHARINDEX(@delimiter, @string)
WHILE @start < LEN(@string) + 1 BEGIN
IF @end = 0
SET @end = LEN(@string) + 1
INSERT INTO @output (splitdata)
VALUES(SUBSTRING(@string, @start, @end - @start))
SET @start = @end + 1
SET @end = CHARINDEX(@delimiter, @string, @start)
END
RETURN
END
go
;with cte
as
(
select t1.ID,t1.userPerms,t1.Name,t3.Perm ,t1.DOB from #tblData as t1
cross apply
dbo.fnsplitstring(t1.userPerms,',') as t2
join #tblPerm as t3
on t3.ID=t2.splitdata
)
select id,STUFF((select ','+perm from cte t1
where t1.ID=t2.id
for XML path('')),1,1,'') as userperms,Name,DOB
from cte t2
group by id ,name,DOB