【问题标题】:how to use MySQL bitwise operations in php?如何在 php 中使用 MySQL 按位运算?
【发布时间】:2012-02-21 21:20:38
【问题描述】:

我试图对我的查询使用 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    ..
...

现在,来自table1id = 3 是'66',这意味着它有64 or movies2 or art

但是

他不是也有两次32 or actor2 or art吗??

希望你能明白我的困惑在哪里。我如何控制我想要返回的结果。在这种情况下,我想要64 or movies2 or art

但有时我希望来自table2 的三个id's 属于来自table1id

有什么想法吗?

谢谢

【问题讨论】:

  • 哇!这是一个糟糕的数据模型。
  • 只是出于好奇,你为什么不使用一个单独跟踪 id -> ptid 关系的表?
  • 你想在 MySQL 中使用按位运算来连接两个表???我的眼睛!护目镜什么都不做!但说真的,正如@jprofitt 所说,为什么不使用更标准的多对多关系模型呢?
  • @Patrioticcow 公平问题。我发布了一个答案,因为它需要的空间比这里可用的空间多。

标签: php mysql bitwise-operators


【解决方案1】:

使用按位或

以下查询返回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

使用按位与而不是或

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

SELECT *
FROM table
WHERE id & 66 <> 0

由于0 = false是MySQL,可以进一步缩写成这样:

SELECT *
FROM table
WHERE id & 66

【讨论】:

    【解决方案2】:
    select * from table2 where id & 66
    

    【讨论】:

      【解决方案3】:

      虽然关于如何在 MySQL 中执行按位运算的问题已经得到解答,但 cmets 中关于为什么这可能不是最佳数据模型的子问题仍然悬而未决。

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

      此连接可以是显式的,例如

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

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

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

      这些选项都不是想法,因为它们不是“sargable”,即数据库无法构造 Search ARGument。因此,您无法使用索引优化查询。查询的成本超出了无法利用索引的范围,因为对于表中的每一行,数据库都必须计算和评估一个表达式。这很快就会变得非常占用内存、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 中的相关行。

      【讨论】:

        【解决方案4】:

        在尝试了 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
        

        【讨论】:

          猜你喜欢
          • 2016-01-09
          • 1970-01-01
          • 1970-01-01
          • 2011-01-09
          • 2011-08-24
          • 2016-01-13
          • 2013-10-21
          • 1970-01-01
          • 2013-04-16
          相关资源
          最近更新 更多