mysql 使用位运算 &|^

参考:
原文:https://blog.csdn.net/21aspnet/article/details/6801116  

原文:https://www.cnblogs.com/goody9807/archive/2012/05/03/2480895.html

在SQL Server ,采用1,2,4,8,16.....等用数字标识的状态字段可以进行累加,对存在的几种状态进行组合,从而可形成各种组合状态

例如:一条记录该字段原来的数字是,2,如我们想加上4,则可以用

update t_User set iFlag = iFlag | 4 where UserID = 1

(iFlag 为该字段名)

例2:在加上4之后我们想去掉4怎么办呢,可以这样实现

update t_User set iFlag = iFlag ^4 where UserID = 1

这样就又把4从该记录中去掉了.

如果我们想选择所有为2的记录该怎么做呢,可以这样实现

select * from t_User where iFlag &2 = 2

SQL中的位运算不但可以取出各种值,而且我们可以对他对数据进行排序

举例如下,新闻列表中的一个字段标识为

1:置顶

2:不置顶

4:推荐

8:不推荐

该字段的值可以为这4种状态的组合,如果我们根据一定条件想把所有置顶的放在前面该如何做呢

select * from t_News order by iFlag & 1 desc

这样我们就把所有置顶的贴子排在前面,当然这里可以加上一定的Where 条件,在Where 里也可可以加一定的位运算,

关于位运算可以查阅相应的SQL 帮助

下面来讲一讲C#中的枚举位运算

这里我们定义一个枚举

    [Flags]
    enum UserFlag
    {
        a = 1,
        b = 2,
        c = 4,
        d = 8,
        e = 16,
        f = 32
    }


在代码里加上如下处理

    protected void Page_Load(object sender, EventArgs e)
    {

        if (!IsPostBack)
        {

            这是第一种写法:   string strSQL = "select * from v_User where iFlag & @iFlag = @iFlag";

          这是第二种写法:   string strSQL = "select * from v_User where  @iFlag | iFlag = iFlag

            //SqlParameter parm = new SqlParameter("@iFlag",SqlDbType.Int,4);
            //parm.Value = UserFlag.a | UserFlag.b ;
            SqlConnection con = new SqlConnection("server=.;database=Sinvan_TexDB;User Id=sa;pwd=123;");

            SqlCommand comm = new SqlCommand(strSQL, con);

            comm.Parameters.Add("@iFlag", SqlDbType.Int, 4).Value = UserFlag.a | UserFlag.b;

            SqlDataAdapter adp = new SqlDataAdapter(comm);
            DataTable dTable = new DataTable();
            adp.Fill(dTable);

            UserFlag userFlag = (UserFlag)Enum.Parse(typeof(UserFlag), dTable.Rows[0][11].ToString()); 

        }
    }


进行处理之后userFlag就是数据库中存在的各种组合

我们同样可对其进行一定的位运算处理

如我们想加上 UserFlag.c 可进行如下操作

userFlag = userFlag | Userflag.c

如想去掉UserFlag.c 可进行如下操作

userFlag = userFlag ^ UserFlag.c

如我们要判断是该标识中是否存在c可进行如下操作

(userFlag & UserFlag.c) == UserFlag.c

是不是与SQL Server 中的操作类似,位运算不管什么语言都是通用的,呵呵

可惜Access 不支持位运算

 

 

select 2|8       --10 
select 2|8|1    --11

select 10&8    --8,包含,10=8+2 
select 10&2    --2,包含,10=2+8 
select 10&4    --0,不包含 
select 19&16  --16,包含,19=16+2+1 
select 19&8    --0,包含,19=16+2+1

select * from SqlBitOperation where FBitTags&4=4

 

在权限中的应用

1、两张表

(1)、操作与权限标志表

if exists (select * from sysobjects where id = OBJECT_ID('[RightTags]') and OBJECTPROPERTY(id, 'IsUserTable') = 1) 
DROP TABLE [RightTags]

CREATE TABLE [RightTags] ( 
[Pkid] [int]  IDENTITY (1, 1)  NOT NULL, 
[RightsName] [nvarchar]  (50) NOT NULL, 
[RightsTag] [int]  NOT NULL DEFAULT (0))

ALTER TABLE [RightTags] WITH NOCHECK ADD  CONSTRAINT [PK_RightTags] PRIMARY KEY  NONCLUSTERED ( [Pkid] ) 

SET IDENTITY_INSERT [RightTags] ON 
INSERT [RightTags] ([Pkid],[RightsName],[RightsTag]) VALUES ( 1,'吃饭',1) 
INSERT [RightTags] ([Pkid],[RightsName],[RightsTag]) VALUES ( 2,'拉屎',2) 
INSERT [RightTags] ([Pkid],[RightsName],[RightsTag]) VALUES ( 3,'打炮',4) 
INSERT [RightTags] ([Pkid],[RightsName],[RightsTag]) VALUES ( 4,'泡妞',8) 
INSERT [RightTags] ([Pkid],[RightsName],[RightsTag]) VALUES ( 5,'生子',16) 
INSERT [RightTags] ([Pkid],[RightsName],[RightsTag]) VALUES ( 6,'包二奶',32) 
SET IDENTITY_INSERT [RightTags] OFF

(2)、用户与权限表

if exists (select * from sysobjects where id = OBJECT_ID('[RightUsers]') and OBJECTPROPERTY(id, 'IsUserTable') = 1) 
DROP TABLE [RightUsers]

CREATE TABLE [RightUsers] ( 
[Pkid] [int]  IDENTITY (1, 1)  NOT NULL, 
[FUser] [nvarchar]  (50) NOT NULL, 
[UserRights] [int]  NOT NULL DEFAULT (0))

ALTER TABLE [RightUsers] WITH NOCHECK ADD  CONSTRAINT [PK_RightUsers] PRIMARY KEY  NONCLUSTERED ( [Pkid] ) 

SET IDENTITY_INSERT [RightUsers] ON 
INSERT [RightUsers] ([Pkid],[FUser],[UserRights]) VALUES ( 1,'张三',7) 
INSERT [RightUsers] ([Pkid],[FUser],[UserRights]) VALUES ( 2,'李四',9) 
INSERT [RightUsers] ([Pkid],[FUser],[UserRights]) VALUES ( 3,'王老板',63) 
INSERT [RightUsers] ([Pkid],[FUser],[UserRights]) VALUES ( 4,'朱麻子',0) 
SET IDENTITY_INSERT [RightUsers] OFF

 

2、访问判断是否有权限

--1.查询权限 
declare @iRights as int 
select @iRights=(select top 1 RightsTag from RightTags where RightsName='打炮') 
--print @iRights 
select * from RightUsers where UserRights&@iRights=@iRights --所有可以打炮的人 
select * from RightUsers where FUser='李四' and UserRights&@iRights=@iRights   --此人是否可以打炮(有无记录集) 
select * from RightUsers where FUser='王老板' and UserRights&@iRights=@iRights --此人是否可以打炮(有无记录集)

go

 

3、设置权限

--2.设置权限 
declare @yourRights int 
select @yourRights=(select sum(RightsTag) from RightTags where RightsName in('吃饭','拉屎','打炮')) 
--print @yourRights

update RightUsers set UserRights=@yourRights where FUser='张三' 
go

 

4、查看此人的所有权限

--3.查看此人的所有权限 
declare @yourRights as int 
select @yourRights=(select UserRights from RightUsers where FUser='李四') 
print @yourRights

select * from RightTags where @yourRights&RightsTag=RightsTag 
go

 

5、检测权限表权限值是否为2的整数次方(操作权限标志的有效性:唯一+2的整数次方)

select power(2,6) --64
select power(2.000,5.500) --45.255

select log(64.000)/log(2.000)--6.0

------------------------------
declare @setNewOperateRightTags int --添加一个新操作权限
set @setNewOperateRightTags=64  --64是2的整数次方
--set @setNewOperateRightTags=63  --63不是2的整数次方

declare @number float
set @number=log(@setNewOperateRightTags)/log(2.000)
--print @number
if(ceiling(@number)=floor(@number))--取最大整数=取最小整数
begin
  print cast(@setNewOperateRightTags as varchar(16)) + '是2的整数次方,可以用作权限标志值'
end
else
begin
  print cast(@setNewOperateRightTags as varchar(16)) + '不是2的整数次方,不能用作权限标志值'
end

————————————————————————————————————————————

————————————————————————————————————————————

与运算 a & b  ,
或运算 a | b ,
异或运算 a ^ b ,

或者
你也可以将 与运算理解为 + 法
例如
1|2 = 3   (1+2 = 3)
1|2|4 = 7 (1+2+4 = 7)

将 异或运算理解为 - 法
例如
3^2 = 1 (3-2 = 1)
3^1 = 2  (3-1 = 2)

最后将 与运算 作为判断
例如
3&2 = 1    (3 = 1 + 2, 由 1和2组成 ,所以判断3&2 = 1 )
3&4 = 0   ( 3 没有由 4组成,所以判断3&4 = 0)

那么位运算有何用处呢, 例如 UNIX系统中的权限, 通常我们所知  权限分为  r 读, w 写, x 执行,其中 它们的权值分别为4,2,1, 所以 如果用户要想拥有这三个权限 就必须  chomd 7  , 即 7=4+2+1 表明 这个用户具有rwx权限,如果只想这个用户具有r,x权限 那么就 chomd 5即可

说道此处就要涉及到数据库了。

通常 我们的数据表中 可能会包含各种状态属性, 例如 blog表中 , 我们需要有字段表示其是否公开,是否有设置密码,是否被管理员封锁,是否被置顶等等。 也会遇到在后期运维中,策划要求增加新的功能而造成你需要增加新的字段。

这样会造成后期的维护困难,数据库增大,索引增大的情况。 这时使用位运算就可以巧妙的解决。

例如

<?php
define('B_PUBLIC',1);  // 公开
define('B_PASSWORD',2);  // 加密
define('B_LOCK',4); // 封锁
define('B_TOP',8); // 置顶
?>

-- 公开blog  给status进行或运算
UPDATE blog SET status = status | 1;
-- 加密blog 给status进行或运算
UPDATE blog SET status = status | 2;
-- 封锁blog
UPDATE blog SET status = status | 4;
-- 解锁blog
UPDATE blog SET status = status ^ 4;
--查询所有被置顶的blog
SELECT * FROM blog WHERE status & 8;

虽然节省了空间,但是由于没有办法对status字段使用索引,所以如何使用来优化查询才是最重点的。 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值