Sql 通过第二个表中的所有记录更新表

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列。右

早上好

我有两张桌子。第一个表(SecurityRules)是安全规则列表:

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如果这确实回答了你的问题,请考虑标记答案接受(在下/下投票箭头下的复选标记)。请参阅“位篡改在编程语言中非常有趣。但是,它通常不是数据库中的最佳方法”。你完全正确。但我认为这是历史性的,不能轻易改变。“在编程语言中,位篡改非常有趣。然而,它通常不是数据库中最好的方法。”。你完全正确。但我认为这是历史性的,不能轻易改变。