有一个权限模块表和一个用户权限组表
权限表字段:
Role_id,Module_id,Value(tinyint)
用户权限组表字段:
User_id,Role_id这里一个用户可以指定多个权限组,而每个权限组里面有可能有重复的模块功能
如何能求出每个用户的具体每个模块的Value值呢?
网上说的位运算Or偷懒的做法就是取其max值,于是我写了如下代码:SELECT r.Module_id, max(r.Value), u.User_id FROM ErpRoleModule AS r INNER JOIN ErpUserRole AS u ON r.Role_id = u.Role_id group by Module_id,user_id看似解决了,其实不然。
因为这里的value是一个Module_id多个功能的合计数
例如:
销售单(是一个module_id),其中
查看:1,Edit:2,Add:4,Delete:8,审核:16
那么对销售单操作的全部功能Value就应该是31
而且用户有可能有多个Role_id,而这些Role_id里面就有可能有重复的Module_id,所以应该用位运算解决。
所以取max是不正确的,而且也不是简单的sum。该如何实现这种位Sum呢?
谢谢!

解决方案 »

  1.   

    module_id
    1,Edit:2,Add:4,Delete:8,审核:16LZ 考虑将module_id 所有可能值建立匹配关系如何?3,1和2
    7  1、2、4
    ...确定这个后,对应module_id 进行拆分列值,role_id  module_id
    1        7
    拆分后,
    role_id  module_id
    1        1
    1        2
    1        4然后去除重复数据。即可。字符串拆分列表参考
    --SQL2000/2005字符串拆分为列表通用函数
    IF OBJECT_ID('f_getstr') IS NOT NULL 
        DROP FUNCTION  f_getstr
    GO
    CREATE FUNCTION f_getstr(
    @s     NVARCHAR(4000),  --待分拆的字符串
    @flag  NVARCHAR(10)=''  --数据分隔符
    )RETURNS @r TABLE(col NVARCHAR(1000))
    AS
    BEGIN
      IF ISNULL(@flag,'')='' AND LEN(ISNULL(@flag,'')+'a')=1
        INSERT @r 
          SELECT SUBSTRING(@s,number+1,1)
          FROM master..spt_values
          WHERE TYPE='p' and number<LEN(@s+'a')-1 
      ELSE 
        INSERT @r
          SELECT SUBSTRING(@s,number,CHARINDEX(@flag,@s+@flag,number)-number)
          FROM master..spt_values
          WHERE TYPE='p' and number<=len(@s+'a') 
             --AND SUBSTRING(@flag+@s,number,1)=@flag --用此条件或下面的条件均可
             AND CHARINDEX(@flag,@flag+@s,number)=number
      RETURN
    END
    GO
      

  2.   

    谢谢二位的答复。没想到我当初这种合并存储Value法会造成如此的麻烦,如果某用户所拥有的脚色中不存在重复的模块问题就没有这个麻烦了。现在还要用取出重复法。这个我还从来未曾用过呢。我还要捉摸捉摸。不过不知道Access里面是否支持?我的系统写的是想可以使用两种数据库的。没有简单办法了吗?
      

  3.   

    我提出的问题可能没有表述清楚,Role_id就是脚色ID,其中包含了好多个模块(Module)的Value。
    这个Value是每模块的n个功能的和。不过OrchidCat提的拆分我倒可以研究研究的。
      

  4.   

    我用了如下语句:SELECT  r.Module_id, r.Value & 1 as vi,r.Value & 2 as ed,r.Value & 4 as ad,r.Value & 8 as de,r.Value & 16 as Ch, u.User_id FROM ErpRoleModule AS r INNER JOIN ErpUserRole AS u ON r.Role_id = u.Role_id  order by User_id ,Module_id结果如下:(片段)
    Module_id vi ed ad de Ch User_id
    mdAdjust 0 2 0 0 0 88092
    mdBeginStocks 0 0 0 0 16 88092
    mdCustomer 0 0 0 8 0 88092
    mdPoIn 0 0 0 0 16 88092
    mdSaleOut 0 0 0 0 16 88092
    mdSaleOut 0 2 0 0 0 88092
    mdSaleOut 0 0 0 8 0 88092
    mdSuppId 1 0 0 8 0 88092
    mdSuppId 0 2 0 0 0 88092
    无法用distinct去除重复,我想如果建一个临时表
    module_id  Value User_id
    然后逐个(按1,2,4,8,16...分别)进行按位与运算,然后在这个临时表中去除重复,再将value进行按w位或求出Value值。是这样吗?我本来想通过一个简单查询得到结果的,现在看来要用存储过程了。
    还有什么好方法吗?
      

  5.   


    access 许多语法与MS SQL 不一样,需要注意。
      

  6.   

    销售单(是一个module_id),其中
    查看:1,Edit:2,Add:4,Delete:8,审核:16个人的观点:
    你的这个权限设定是不是移植别人的?
    二进制ASCII对照表,看看这个,是不是对你有启发
    1的ASCII是00000001
    2的ASCII是00000010
    4的ASCII是00000100
    8的ASCII是00001000
    16的ASCII是00010000
      

  7.   

    补充下:
    31的二进制ASCII是00011111
    根据第一位的0,1判断‘查看’权限
    根据第二位的0,1判断‘Edit’权限
    根据第三位......具体的可以去测试下,如果想了解详细理论的联系我
    QQ:511683001
    可以一起讨论下,因为我只是了解理论,具体的实现没有做过
      

  8.   

    上面说的没错,6年前我就有这个想法,实现windows Server用户角色管理的方式,当时想好了采用2的N次方定义某个功能,也就是按位定义,取值就是1,2,4,8...这样几个功能组合不会有重复的值。一年前在我的一个项目里做了这种三级控制(一个用户、一个角色、一个权限),可以直接给用户赋权限,也可以将权限赋给角色,将角色赋给用户。可以混合使用这两种赋值方式。并且根据这些只获取用户对应的菜单显示或者可用否。可以将用户的直接权限与用户的角色权限在获取菜单时进行位或运算求出实际权限值。本以为都好了。今天才发现,一个用户写的多个角色如果有相同的模块,没法计算其模块该有的实际值。当然今晚是用了对结果集再次操作获得了正确结果。那么sql 语句里就没有这种位运算聚合函数吗?linq也没有吗?我是用的datatable填充法解决的。