我有一个包含ClientID,Name
列的客户端表ClientID|Name
1 |A
2 |B
3 |C
4 |D
5 |E
包含列的Users表:UserID,AllowedClients,DeniedClients
USERID |AllowedClients|DeniedClients
U1 |1,2,5 |NULL
U2 |2,1 |NULL
U3 |1,4,5 |NULL
U4 |5,1,3 |NULL
U5 |2,3 |NULL
目前所有DeniedClients都设置为NULL。
我需要更新用户表, 类似的东西:
Update users set DeniedClients= (All existing ClientIDs in Client table) –` (users.AllowedClients)
输出:
USERID |AllowedClients|DeniedClients
U1 |1,2,5 |3,4
U2 |2,1 |3,4,5
U3 |1,4,5 |2,3
U4 |5,1,3 |2,4
U5 |2,3 |1,4,5
如何在不使用游标的情况下编写此查询。
答案 0 :(得分:1)
正如其他人所说,结构很糟糕......但仍有办法实现,这就是我在T-SQL中的表现......
编辑:修复了1与1匹配的部分...需要更多测试,但正在寻找
if object_id('tempdb..#Client') is not null drop table #Client
create table #Client (ClientID int, Name nvarchar(5))
insert into #Client(ClientID, Name)
values
(1, 'A'),
(2, 'B'),
(3, 'C'),
(4, 'D'),
(5, 'E'),
(11, 'F')
if object_id('tempdb..#Users') is not null drop table #Users
create table #Users (UserID nvarchar(5),AllowedClients nvarchar(50),
DeniedClients nvarchar(50) null)
insert into #Users (UserID, AllowedClients)
values
('U1', '1, 2, 5'),
('U2', '2, 1'),
('U3', '1, 4, 5'),
('U4', '5, 1, 3'),
('U5', '2, 3'),
('U6', '11, 4, 5')
update usr1
set DeniedClients = (STUFF((SELECT ', ' + cast(clt.ClientID as nvarchar)
from #Users usr
join #Client clt
on (usr.AllowedClients not like
'%' + cast(clt.ClientID as nvarchar) + '%' and
SUBSTRING(usr.AllowedClients,
PATINDEX('%' + cast(clt.ClientID as nvarchar) + '%' ,
usr.AllowedClients) + 1, 1) <> cast(clt.ClientID as nvarchar))
or
(usr.AllowedClients like
'%' + cast(clt.ClientID as nvarchar) + '%' and
SUBSTRING(usr.AllowedClients,
PATINDEX('%' + cast(clt.ClientID as nvarchar) + '%' ,
usr.AllowedClients) + 1, 1) = cast(clt.ClientID as nvarchar))
where usr.UserID = usr1.UserID
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'),1,1,''))
from #Users usr1
select * from #Users
答案 1 :(得分:0)
以下输出由以下代码生成:
DECLARE @Client TABLE
(
[ClientID] TINYINT
,[Name] VARCHAR(12)
)
INSERT INTO @Client ([ClientID], [Name])
VALUES (1, 'A')
,(2, 'B')
,(3, 'C')
,(4, 'D')
,(5, 'E');
DECLARE @Users TABLE
(
[UserID] CHAR(2)
,[AllowedClients] VARCHAR(32)
,[DeniedClients] VARCHAR(32)
);
INSERT INTO @Users ([UserID], [AllowedClients], [DeniedClients])
VALUES ('U1', '1,2,5', NULL)
,('U2', '2,1', NULL)
,('U3', '1,4,5', NULL)
,('U4', '5,1,3', NULL)
,('U5', '2,3', NULL);
WITH DataSource ([UserID], [ClientID]) AS
(
-- getting all combinations
SELECT U.[UserID]
,C.[ClientID]
FROM @Users U
CROSS APPLY @Client C
-- excluding current values
EXCEPT
-- getting current values
SELECT [UserID]
,T.c.value('(./text())[1]', 'nvarchar(4000)') [ClientID]
FROM @Users U
CROSS APPLY
(
SELECT x = CONVERT(XML, '<i>' + REPLACE([AllowedClients], ',', '</i><i>') + '</i>').query('.')
) DS
CROSS APPLY x.nodes('i') AS T(c)
)
SELECT DISTINCT DS1.[UserID]
,DS.[CSV]
FROM DataSource DS1
CROSS APPLY
(
SELECT STUFF
(
(
SELECT CONCAT(',', DS2.[ClientID])
FROM DataSource DS2
WHERE DS1.[UserID] = DS2.[UserID]
FOR XML PATH(''), TYPE
).value('.', 'varchar(max)')
,1
,1
,''
)
) DS(CSV)
您现在可以执行更新。
如果这是一个真实的项目并且有很多记录,那么规范化数据会更快。如果由于其他原因而坚持使用CSV格式,则应编写一些CLR函数来分割/连接值。