Sql 通过第二个表中的所有记录更新表
早上好 我有两张桌子。第一个表(SecurityRules)是安全规则列表:Sql 通过第二个表中的所有记录更新表,sql,sql-server,sql-update,Sql,Sql Server,Sql Update,早上好 我有两张桌子。第一个表(SecurityRules)是安全规则列表: ID srRight srRole 1 4 NULL 2 2 32 第二个表(项目)是项目列表: ProjId prRight prRole 1 0 NULL 2 0 32 3 0 NULL 我需要使用SecurityRules中的所有记录更新项目列表,并根据两个表中的角色更新prRight列。右
ID srRight srRole
1 4 NULL
2 2 32
第二个表(项目)是项目列表:
ProjId prRight prRole
1 0 NULL
2 0 32
3 0 NULL
我需要使用SecurityRules中的所有记录更新项目列表,并根据两个表中的角色更新prRight
列。右侧的值是按位组织的。
我使用以下SQL更新查询来完成此操作:
Update Projects
-- Perform binary sum
Set prRight = prRight | srRight
From SecurityRules
Where (srRole is Null) --Always apply srRight if srRole is not defined
OR (srRole is Not Null And srRole=prRole) --Apply right if both roles are equal
预期结果是:
ProjId prRight prRole
1 4 NULL
2 6 32
3 4 NULL
但我得到:
ProjId prRight prRole
1 4 NULL
2 4 32
3 4 NULL
看起来更新只由SecurityRules表的第一条记录完成。我需要将SecurityRules表中的所有记录应用于Project表的所有记录。
如果我创建一个简单的循环,并手动循环SecurityRules中的所有记录,它工作得很好,但是如果必须将10个安全规则与2000个项目进行比较,则性能非常差
有什么建议吗
Arno此答案基于中用于生成按位OR值的代码。它使用CTE为每个权限值生成一个位掩码,然后按位或通过对每个权限值中存在的不同位掩码求和生成整体掩码。最后一次CTE的输出用于更新项目表:
WITH Bits AS (
SELECT 1 AS BitMask
UNION ALL
SELECT 2 * BitMask FROM Bits
WHERE BitMask < 65536
),
NewRights AS (
SELECT ProjId, SUM(DISTINCT BitMask) AS NewRight
FROM Projects p
JOIN SecurityRules s ON s.srRole IS NULL OR s.srRole = p.prRole
JOIN Bits b ON b.BitMask & s.srRight > 0
GROUP BY ProjID
)
UPDATE p
SET p.prRight = n.NewRight
FROM Projects p
JOIN NewRights n ON n.ProjId = p.ProjId
ProjId prRight prRole
1 4 null
2 6 32
3 4 null
此答案基于中用于生成按位OR值的代码。它使用CTE为每个权限值生成一个位掩码,然后按位或通过对每个权限值中存在的不同位掩码求和生成整体掩码。最后一次CTE的输出用于更新项目表:
WITH Bits AS (
SELECT 1 AS BitMask
UNION ALL
SELECT 2 * BitMask FROM Bits
WHERE BitMask < 65536
),
NewRights AS (
SELECT ProjId, SUM(DISTINCT BitMask) AS NewRight
FROM Projects p
JOIN SecurityRules s ON s.srRole IS NULL OR s.srRole = p.prRole
JOIN Bits b ON b.BitMask & s.srRight > 0
GROUP BY ProjID
)
UPDATE p
SET p.prRight = n.NewRight
FROM Projects p
JOIN NewRights n ON n.ProjId = p.ProjId
ProjId prRight prRole
1 4 null
2 6 32
3 4 null
如果我理解正确,您在srRole
列中有一个直接匹配项,然后是适用于所有人的默认规则
最简单的方法(在本例中)是在更新
中使用join
s:
update p
Set prRight = p.prRight | srn.srRight | coalesce(sr.srRight, 0)
From Projects p join
SecurityRules srn
on srRole is null left join
SecurityRules sr
on sr.srRole = p.prRole;
他是一把小提琴
假设没有默认规则,您可能会更安全。而prRight
可以是NULL
:
update p
Set prRight = coalesce(p.prRight, 0) | coalesce(srn.srRight, 0) | coalesce(sr.srRight, 0)
From Projects p left join
SecurityRules srn
on srRole is null left join
SecurityRules sr
on sr.srRole = p.prRole;
我建议你考虑修改你的数据模型。在编程语言中,位摆弄非常有趣。然而,它通常不是数据库中的最佳方法。除非您的应用程序确实需要位开关,否则请改用连接表。如果我理解正确,您在srRole
列上有一个直接匹配项,然后是适用于所有人的默认规则
最简单的方法(在本例中)是在更新
中使用join
s:
update p
Set prRight = p.prRight | srn.srRight | coalesce(sr.srRight, 0)
From Projects p join
SecurityRules srn
on srRole is null left join
SecurityRules sr
on sr.srRole = p.prRole;
他是一把小提琴
假设没有默认规则,您可能会更安全。而prRight
可以是NULL
:
update p
Set prRight = coalesce(p.prRight, 0) | coalesce(srn.srRight, 0) | coalesce(sr.srRight, 0)
From Projects p left join
SecurityRules srn
on srRole is null left join
SecurityRules sr
on sr.srRole = p.prRole;
我建议你考虑修改你的数据模型。在编程语言中,位摆弄非常有趣。然而,它通常不是数据库中的最佳方法。除非您的应用程序确实需要位开关,否则请改用连接表。是的,这是可行的。该示例是实际情况的简单表示,其中角色也是按位运算符,只需将s.srRole=p.prRole替换为(s.srRole&p.prRole)>0,此直接操作即可。伟大的Thanks@ArnoVoerman如果这确实回答了你的问题,请考虑标记答案接受(在下/下投票箭头下的复选标记)。看,是的,这是有效的。该示例是实际情况的简单表示,其中角色也是按位运算符,只需将s.srRole=p.prRole替换为(s.srRole&p.prRole)>0,此直接操作即可。伟大的Thanks@ArnoVoerman如果这确实回答了你的问题,请考虑标记答案接受(在下/下投票箭头下的复选标记)。请参阅“位篡改在编程语言中非常有趣。但是,它通常不是数据库中的最佳方法”。你完全正确。但我认为这是历史性的,不能轻易改变。“在编程语言中,位篡改非常有趣。然而,它通常不是数据库中最好的方法。”。你完全正确。但我认为这是历史性的,不能轻易改变。