【问题标题】:Update table by all records from second table通过第二个表中的所有记录更新表
【发布时间】:2020-05-04 23:59:08
【问题描述】:

早上,

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

ID  srRight srRole
1   4       NULL    
2   2       32  

第二个表(项目)是项目列表:

ProjId  prRight prRole
1       0       NULL
2       0       32
3       0       NULL

我需要使用 SecurityRules 中的所有记录更新项目列表,并根据两个表中的角色更新 prRight 列。 Right 值是按位组织的。 我使用以下 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 个项目进行比较,则性能非常差......

有什么建议吗?

阿诺

【问题讨论】:

    标签: sql sql-server sql-update


    【解决方案1】:

    此答案基于this answer 中的代码,用于生成值的按位或。它使用 CTE 为每个权限值生成一个位掩码,然后通过对每个权限值中存在的不同位掩码求和来生成整体按位或。然后使用最后一个 CTE 的输出来更新 Projects 表:

    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 
    

    结果Projects 表:

    ProjId  prRight     prRole
    1       4           null
    2       6           32
    3       4           null
    

    Demo on dbfiddle

    【讨论】:

    • 是的,这行得通。该示例是实际情况的简单表示,其中角色也是按位运算符,只需将 s.srRole = p.prRole 替换为 (s.srRole & p.prRole) >0,此直接即可工作。伟大的。谢谢
    • @ArnoVoerman 如果这确实回答了您的问题,请考虑将答案标记为已接受(答案旁边的向上/向下投票箭头下方的复选标记)。见stackoverflow.com/help/someone-answers
    【解决方案2】:

    如果我理解正确,您可以直接匹配 srRole 列,然后是适用于所有人的默认规则。

    最简单的方法(在这种情况下)是在update 中使用joins:

    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;
    

    Here 是一个 dbfiddle。

    假设没有默认规则,您可能会更安全。而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;
    

    也就是说,我建议您考虑修改您的数据模型。位摆弄在编程语言中很有趣。但是,它通常不是数据库中的最佳方法。而是使用联结表,除非您的应用程序确实需要位开关。

    【讨论】:

    • “位摆弄在编程语言中很有趣。但是,它通常不是数据库中的最佳方法”。你是绝对正确的。但我这是历史性的,不能那么容易改变。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多