我试图将一个表合并到另一个表(我们称之为Stage和Prod)来控制用户及其权限。我的最终结果应该是一个Prod表,它将每个用户ID的权限从Stage合并到Prod。我遇到的问题是,这些表是由外部供应商设计的,并在一个以逗号分隔的列中包含多条信息。
舞台可能如下所示:
Userid | Permissions
----------------------------------------------------------------
1 | schedule,upload,test,download,admin
2 | test,upload
3 | download
PROD:
Userid | Permissions
----------------------------------------------------------------
1 | test,admin,schedule,download,upload
2 | admin
3 | download,upload
当他们合并时,用户ID应该拥有Stage的权限,并与Prod中的权限相结合。但是,当权限是逗号分隔的字符串时解决这个问题让我有机会结束。
在下面的最终结果中,用户ID 1的权限保持不变,因为它们在Stage中与Prod中的相同,只是顺序不同。 Userid 2已将他的Stage权限添加到他的Prod,因为他还没有这些权限。 用户ID 3的Prod权限不变,因为他的Stage权限已经包含在内。
结果:
Userid | Permissions
----------------------------------------------------------------
1 | test,admin,schedule,download,upload
2 | admin,test,upload
3 | download,upload
有没有办法做到这一点?希望这有一定道理,但如果有更多的信息可以帮助我,我很乐意尝试提供它。谢谢你的任何帮助。
答案 0 :(得分:0)
有趣的是,这是MSSQLTips blog Aaron Bertrand讨论的主题。借用他的代码,您可以创建Numbers
表和字符串拆分/重组功能,以便进行以下工作。如果你打算经常这样做并且坚持你所展示的架构,那么这就是你要走的路。
/*Create Test Data
create table StagePermissions (UserID int, [Permissions] nvarchar(max));
create table ProdPermissions (UserID int, [Permissions] nvarchar(max));
insert StagePermissions values
(1,'schedule,upload,test,download,admin'),
(2,'test,upload'),
(3,'download')
insert ProdPermissions values
(1,'test,admin,schedule,download,upload'),
(2,'admin'),
(3,'download,upload')
*/
select sp.UserID, dbo.ReassembleString(sp.Permissions+','+pp.Permissions,',',N'OriginalOrder') MergedPermissions
from StagePermissions sp
join ProdPermissions pp on pp.UserID=sp.UserID
答案 1 :(得分:0)
采用史蒂夫的测试数据,但添加:
create table BothPermissions (UserID int, [Permissions] nvarchar(max));
此代码将使用固定数量的可能权限。
DECLARE @XPermissions TABLE (
UserID int
,XSchedule BIT
,XUpload BIT
,XTest BIT
,XDownload BIT
,XAdmin BIT
)
INSERT INTO @XPermissions
SELECT
ISNULL(sp.UserID,pp.UserID),
CHARINDEX('schedule',sp.[Permissions]) + CHARINDEX('schedule',pp.[Permissions]),
CHARINDEX('upload',sp.[Permissions]) + CHARINDEX('upload',pp.[Permissions]),
CHARINDEX('test',sp.[Permissions]) + CHARINDEX('test',pp.[Permissions]),
CHARINDEX('download',sp.[Permissions]) + CHARINDEX('download',pp.[Permissions]),
CHARINDEX('admin',sp.[Permissions]) + CHARINDEX('admin',pp.[Permissions])
FROM StagePermissions sp
FULL JOIN ProdPermissions pp
ON sp.UserID = pp.UserID
INSERT INTO BothPermissions
SELECT
UserID,
CASE XSchedule WHEN 0 THEN '' ELSE 'schedule ' END +
CASE XUpload WHEN 0 THEN '' ELSE 'upload ' END +
CASE XTest WHEN 0 THEN '' ELSE 'test ' END +
CASE XDownload WHEN 0 THEN '' ELSE 'download ' END +
CASE XAdmin WHEN 0 THEN '' ELSE 'admin' END
FROM @XPermissions
UPDATE BothPermissions
SET [Permissions] = REPLACE(RTRIM([Permissions]),' ',', ')
现在,我对史蒂夫的回答更加好奇。我认为这是最强大的解决方案。但是,我想知道它如何使用大型数据集。我仍然不知道答案,因为我还没有设置使用它所需的工具。但这是一个包含一些随机数生成的查询,用于填充每个记录的10,000条记录:
SELECT GETDATE()
DECLARE @StagePerms TABLE (
UserID INT IDENTITY
,Perms NVARCHAR(MAX)
)
DECLARE @ProdPerms TABLE (
UserID INT IDENTITY
,Perms NVARCHAR(MAX)
)
DECLARE @Counter INT = 0
DECLARE @XString NVARCHAR(MAX)
WHILE @Counter < 10000
BEGIN
SET @Counter += 1
SET @XString = REPLACE(RTRIM(
CASE ROUND(RAND()-.2,0) WHEN 0 THEN '' ELSE 'test ' END +
CASE ROUND(RAND()-.2,0) WHEN 0 THEN '' ELSE 'admin ' END +
CASE ROUND(RAND()-.2,0) WHEN 0 THEN '' ELSE 'schedule ' END +
CASE ROUND(RAND()-.2,0) WHEN 0 THEN '' ELSE 'download ' END +
CASE ROUND(RAND()-.2,0) WHEN 0 THEN '' ELSE 'upload ' END)
,' ',', ')
INSERT INTO @StagePerms SELECT @XString
SET @XString = REPLACE(RTRIM(
CASE ROUND(RAND()-.2,0) WHEN 0 THEN '' ELSE 'test ' END +
CASE ROUND(RAND()-.2,0) WHEN 0 THEN '' ELSE 'admin ' END +
CASE ROUND(RAND()-.2,0) WHEN 0 THEN '' ELSE 'schedule ' END +
CASE ROUND(RAND()-.2,0) WHEN 0 THEN '' ELSE 'download ' END +
CASE ROUND(RAND()-.2,0) WHEN 0 THEN '' ELSE 'upload ' END)
,' ',', ')
INSERT INTO @ProdPerms SELECT @XString
END
SELECT GETDATE()
DECLARE @BothPerms TABLE (
UserID INT
,Perms NVARCHAR(MAX)
)
DECLARE @XPerms TABLE (
UserID int
,XSchedule BIT
,XUpload BIT
,XTest BIT
,XDownload BIT
,XAdmin BIT
)
INSERT INTO @XPerms
SELECT
ISNULL(sp.UserID,pp.UserID),
CHARINDEX('schedule',sp.Perms) + CHARINDEX('schedule',pp.Perms),
CHARINDEX('upload',sp.Perms) + CHARINDEX('upload',pp.Perms),
CHARINDEX('test',sp.Perms) + CHARINDEX('test',pp.Perms),
CHARINDEX('download',sp.Perms) + CHARINDEX('download',pp.Perms),
CHARINDEX('admin',sp.Perms) + CHARINDEX('admin',pp.Perms)
FROM @StagePerms sp
FULL JOIN @ProdPerms pp
ON sp.UserID = pp.UserID
INSERT INTO @BothPerms
SELECT
UserID,
CASE XTest WHEN 0 THEN '' ELSE 'test ' END +
CASE XAdmin WHEN 0 THEN '' ELSE 'admin ' END +
CASE XSchedule WHEN 0 THEN '' ELSE 'schedule ' END +
CASE XDownload WHEN 0 THEN '' ELSE 'download ' END +
CASE XUpload WHEN 0 THEN '' ELSE 'upload ' END
FROM @XPerms
UPDATE @BothPerms
SET Perms = REPLACE(RTRIM(Perms),' ',', ')
SELECT * FROM @BothPerms
SELECT GETDATE()
随机数生成不到一秒钟;其余的大约需要31秒。史蒂夫,我有兴趣看一下比较。显然,如果数据不允许我的解决方案,则无关紧要。而且我确定某处有一个甜蜜的地方。
答案 2 :(得分:0)
请使用以下查询。它在SQL Server 2012中运行良好。
DECLARE @Stage TABLE (Userid int, Permission Varchar (8000))
DECLARE @Prod TABLE (Userid int, Permission Varchar (8000))
DECLARE @temp TABLE (Userid int, Permission Varchar (8000))
INSERT @Stage
(Userid,Permission)
VALUES
(1,'schedule,upload,test,download,admin'),
(2,'test,upload'),
(3,'download')
INSERT @Prod
(Userid,Permission)
VALUES
(1,'test,admin,schedule,download,upload'),
(2,'admin'),
(3,'download,upload')
-- Execution Part
INSERT INTO @temp
(Userid,Permission)
(
SELECT A.Userid AS Userid,Split.a.value('.', 'VARCHAR(100)') AS Permission FROM
(SELECT Userid,CAST ('<M>' + REPLACE(Permission, ',', '</M><M>') + '</M>' AS XML) AS Permission FROM @Stage A) AS A
CROSS APPLY Permission.nodes ('/M') AS Split(a)
UNION
SELECT A.Userid AS Userid,Split.a.value('.', 'VARCHAR(100)') AS Permission FROM
(SELECT Userid,CAST ('<M>' + REPLACE(Permission, ',', '</M><M>') + '</M>' AS XML) AS Permission FROM @Prod A) AS A
CROSS APPLY Permission.nodes ('/M') AS Split(a)
)
SELECT Userid, Permission =
STUFF((SELECT ', ' + Permission
FROM @temp b
WHERE b.Userid = a.Userid
FOR XML PATH('')), 1, 2, '')
FROM @temp a
GROUP BY Userid
输出
Userid Permission
1 admin, download, schedule, test, upload
2 admin, test, upload
3 download, upload
答案 3 :(得分:0)
您还可以使用SQL Serv 2016中引入的string splitting的直接支持(如果您当然已经开始使用此引擎版本:)) STRING_SPLIT返回单列表...