如何在PHP中使用MySQL按位运算?

时间:2012-02-21 21:20:38

标签: php mysql bitwise-operators

我试图对我的查询使用MySQL按位操作,我有这个例子:

table1
id      ptid
1       3
2       20
3       66
4       6

table2
id     types
1      music
2      art
4      pictures
8      video
16     art2
32     actor
64     movies
128    ..
...

现在,来自id = 3的{​​{1}}为'66',这意味着它有table164 or movies

他也没有2 or art两次和32 or actor ??

希望你看到我的困惑在哪里。我如何控制我想要的结果。在这种情况下,我想要2 or art64 or movies

但有时我希望2 or art中的三个id's属于来自table2的{​​{1}}

任何想法?

由于

4 个答案:

答案 0 :(得分:11)

使用按位OR

以下查询返回66中表2中的所有项目:

SELECT *
FROM table2
WHERE id | 66 = 66

但是32 + 32 = 64?

虽然32 + 32 = 64,但它不会影响我们。

这是二进制64:

01000000

这是二进制的32:

00100000

这是二进制中的2:

00000010

这是我们在这种情况下使用的1的位置,而不是值。不会有两件事。每个标志都打开或关闭。

这是二进制的66。请注意,64和2已打开,而不是32:

01000010

使用按位AND代替OR

编写查询的另一种方法是使用按位AND,如下所示:

SELECT *
FROM table
WHERE id & 66 <> 0

0 = false到MySQL,它可以进一步缩写为:

SELECT *
FROM table
WHERE id & 66

答案 1 :(得分:4)

select * from table2 where id & 66

答案 2 :(得分:4)

虽然已经回答了关于如何在MySQL中执行按位运算的问题,但是评论中关于为什么这可能不是最佳数据模型的子问题仍然很突出。

在给出的例子中,有两个表;一个带有位掩码,另一个带有每个位代表的分解。这意味着,在某些时候,必须将两个表连接在一起以返回/显示各个位的含义。

此联接可以是明确的,例如

SELECT * 
FROM Table1 
    INNER JOIN TABLE2 
        ON table1.ptid  & table2.id <> 0

或者隐含在哪里可以从table1中选择数据到您的应用程序中,然后再次调用查找位掩码值,例如。

SELECT * 
FROM table2
WHERE id & $id <> 0 

这些选项都不是想法,因为它们不是“sargable”,即数据库无法构建Search ARGument。因此,您无法使用索引优化查询。查询的成本超出了无法利用索引的范围,因为对于表中的每一行,DB必须计算和计算表达式。这非常快速地变成了内存,CPU和I / O密集型,如果不从根本上改变表结构就无法进行优化。

除了完全无法优化查询之外,读取数据,报告数据也很尴尬,并且您还可能遇到限制添加更多位(8位列中的64个值现在可能没问题,但是不一定总是如此。它们也使系统难以理解,我认为这种设计违反了第一范式。

尽管在数据库中使用位掩码通常是设计不良的标志,但有时候使用它们也没关系。实现多对多关系真的不是那个时代之一。

实现此类关系的典型方法如下所示:

table1 
Id        Val1         Val2
---------------------------
1         ABC          DEF
2         ABC          DEF
3         ABC          DEF
4         ABC          DEF
5         ABC          DEF
6         ABC          DEF

table2
id     types
-------------
1      music
2      art
3      pictures
4      video
5      art2
6      actor
7      movies

table1-table2-relationshitp
table1ID    Table2ID
---------------------
1           1
1           2 
2           3
2           5
3           2
3           7
...

你会这样查询数据

SELECT table1.*, table2.types
FROM table1 
     INNER JOIN table1-table2-relationship 
          ON table1.id = table1-table2-relationship.table1id
     INNER JOIN table2 
          ON table1-table2-relationship.table2.id = table2.id

根据这些表的访问模式,您通常会将关系表上的两列作为复合索引(我通常将它们视为复合主键)。此索引将允许数据库快速查找相关的关系表中的行然后查找table2中的相关行。

答案 3 :(得分:0)

在回答了Marcus Adams的回答之后,我想我还提供了另一个帮助我了解如何使用按位操作连接两个表的示例。

考虑下面的样本数据,它定义了一个元音表,以及一个单词表,其中一个值表示该单词中存在的元音。

# Create sample tables.
drop temporary table if exists Vowels;
create temporary table Vowels 
(
    Id int, 
    Letter varchar(1)
);
drop temporary table if exists Words;
create temporary table Words
(
    Word varchar(20),
    Vowels int
);

# Insert sample data.
insert into Vowels
    select 1,   'a' union all
    select 2,   'e' union all
    select 4,   'i' union all
    select 8,   'o' union all
    select 16,  'u';
insert into Words 
    select 'foo',           8  union all 
    select 'hello',         10 union all
    select 'language',      19 union all
    select 'programming',   13 union all
    select 'computer',      26;      

我们现在可以将Vowel表加入Word表,如下所示:

# List every word with its vowels.
select Word, Vowels, Letter, Id as 'Vowel Id'
from (
    select *
    from Words
) w
join Vowels v
where v.Id | w.Vowels = w.Vowels
order by Word, Letter;

当然,我们可以将任何条件应用于内部查询。

# List the letters for just the words with a length < 6
select Letter
from (
    select *
    from Words
    where length(Word) < 6
) w
join Vowels v
where v.Id | w.Vowels = w.Vowels
order by Word, Letter