sql位运算问题

cnwin 2011-07-07 12:38:12
有一个权限模块表和一个用户权限组表
权限表字段:
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呢?
谢谢!
...全文
368 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
快溜 2011-07-07
  • 打赏
  • 举报
回复
可以用去除重复吧
cnwin 2011-07-07
  • 打赏
  • 举报
回复
上面说的没错,6年前我就有这个想法,实现windows Server用户角色管理的方式,当时想好了采用2的N次方定义某个功能,也就是按位定义,取值就是1,2,4,8...这样几个功能组合不会有重复的值。一年前在我的一个项目里做了这种三级控制(一个用户、一个角色、一个权限),可以直接给用户赋权限,也可以将权限赋给角色,将角色赋给用户。可以混合使用这两种赋值方式。并且根据这些只获取用户对应的菜单显示或者可用否。可以将用户的直接权限与用户的角色权限在获取菜单时进行位或运算求出实际权限值。本以为都好了。今天才发现,一个用户写的多个角色如果有相同的模块,没法计算其模块该有的实际值。当然今晚是用了对结果集再次操作获得了正确结果。那么sql 语句里就没有这种位运算聚合函数吗?linq也没有吗?我是用的datatable填充法解决的。
cd731107 2011-07-07
  • 打赏
  • 举报
回复
其实现在一般使用三级控制,第一个是所有的权限表,第二是根据权限表配置角色表,
第三给人员配置对应的角色
赛里木 2011-07-07
  • 打赏
  • 举报
回复
补充下:
31的二进制ASCII是00011111
根据第一位的0,1判断‘查看’权限
根据第二位的0,1判断‘Edit’权限
根据第三位......

具体的可以去测试下,如果想了解详细理论的联系我
QQ:511683001
可以一起讨论下,因为我只是了解理论,具体的实现没有做过
赛里木 2011-07-07
  • 打赏
  • 举报
回复
销售单(是一个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
Mr_Nice 2011-07-07
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 cnwin 的回复:]

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

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

cnwin 2011-07-07
  • 打赏
  • 举报
回复
我用了如下语句:

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值。是这样吗?我本来想通过一个简单查询得到结果的,现在看来要用存储过程了。
还有什么好方法吗?

cnwin 2011-07-07
  • 打赏
  • 举报
回复
我提出的问题可能没有表述清楚,Role_id就是脚色ID,其中包含了好多个模块(Module)的Value。
这个Value是每模块的n个功能的和。不过OrchidCat提的拆分我倒可以研究研究的。
cnwin 2011-07-07
  • 打赏
  • 举报
回复
谢谢二位的答复。没想到我当初这种合并存储Value法会造成如此的麻烦,如果某用户所拥有的脚色中不存在重复的模块问题就没有这个麻烦了。现在还要用取出重复法。这个我还从来未曾用过呢。我还要捉摸捉摸。不过不知道Access里面是否支持?我的系统写的是想可以使用两种数据库的。没有简单办法了吗?
Mr_Nice 2011-07-07
  • 打赏
  • 举报
回复
module_id
1,Edit:2,Add:4,Delete:8,审核:16

LZ 考虑将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


22,298

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧