【问题标题】:How apply a bitmask to an integer in MySQL?如何将位掩码应用于 MySQL 中的整数?
【发布时间】:2014-07-12 21:35:52
【问题描述】:

问题来了:

数据库 Rx30 将处方状态存储在名为“Rxstatus”的字段中。他们存储的数字是一个永远不会高于 255 的整数。设置的位决定脚本是否被填充。

一位代表告诉我们,如果设置了 16、32 或 128,则脚本被视为“未填充”。

所以现在我们需要做的是取一个整数,比如“49”,然后查看设置了哪些位。为了速度,这需要通过 MySQL 完成。我知道 49 是:

32+16+1 = 49

所以这个字段设置了16,所以脚本是空的。

我如何(在 MySQL 中)获取一个整数,例如 152,并确定它的哪些位被设置?

一旦我们确定设置了什么,如果设置了 16、32 或 128,我们可以认为脚本未填充并产生正确的结果。

【问题讨论】:

  • 你的意思可能是从一个字节转换而来,因为一个位甚至不能高于 1 :)
  • 是的,很抱歉!
  • 你说的是一种常见的结构,叫做位掩码。
  • 你可以使用 MySQL 的Bit functions,即按位与 16 或 32 或 128。

标签: mysql type-conversion integer


【解决方案1】:

如果您有测试位掩码,例如32+16+1 = 49,你想知道Rxstatus中是否设置了任何,你可以使用:

SELECT Rxstatus & 49 != 0

如果您想知道是否设置了所有,请使用:

SELECT Rxstatus & 49 = 49

要设置位掩码中的所有位,请执行以下操作:

UPDATE Rx30
SET Rxstatus = Rxstatus | 49
WHERE <condition>

要取消设置位掩码中的所有位,请执行以下操作:

UPDATE Rx30
SET Rxstatus = Rxstatus & ~49
WHERE <condition>

【讨论】:

  • 澄清所提出的具体问题:OP 询问如何知道是否设置了“16、32 或 128”中的任何一个。这些总和是“176”,所以他的解决方案是SELECT Rxstatus &amp; 176 != 0。或者为了更容易看到正在测试的位,请以二进制形式提供测试值:SELECT Rxstatus &amp; b'10110000' != 0
  • ... 或者,如果您更喜欢使用位值的十进制表示:SELECT Rxstatus &amp; (128|32|16) != 0
【解决方案2】:

&amp;一样使用MySQL BIT functions

select Rxstatus & 2 = 2 as 2_set, 
       Rxstatus & 4 = 4 as 4_set,
       Rxstatus & 8 = 8 as 8_set,
       Rxstatus & 16 = 16 as 16_set,
       Rxstatus & 32 = 32 as 32_set,
       Rxstatus & 64 = 64 as 64_set,
       Rxstatus & 128 = 128 as 128_set
from your_table

SQLFiddle demo

【讨论】:

    【解决方案3】:

    您可以将数字转换为二进制,这样您就可以看到设置了哪些位。

    为此,您可以使用CONV() function,例如,您可以将数字 49 从十进制转换为二进制,如下所示:

    SELECT CONV(49,10,2);
    

    导致110001

    【讨论】:

    • 未来读者:不要使用CONV。在查看(脆弱)接受的答案后,我发现使用 CONV 是一个错误。因为返回的字符串的长度会有所不同,具体取决于数字 - 所以很难找到特定的位。改用位掩码 - 请参阅上面的其他答案。
    • 为什么会很困难?如果您想知道第 4 位并且您的字符串长度为 3,则仅表示它是 0
    • 这很难因为字符串长度会根据值的大小而变化。考虑从 0 到 255 的值。CONV 将返回长度从 1 到 8 的字符串。现在,编写一个简单的公式来测试值为 16 的位。它一团糟——你必须处理 8 种不同的字符串长度。可能,但不实用。 (这也是低效的,因为您要将数字转换为字符串,然后从字符串中提取字符。但这不是一个重要的问题。)现在尝试测试多个位。与顶级方法比较:SELECT Rxstatus &amp; 176 != 0.
    【解决方案4】:

    在这里查看了一些答案并与一些同事讨论后,我们通过检查转换后的长度得到了正确的结果:

    LENGTH( CONV( Rxstatus, 10, 2 ) ) NOT IN ( 5, 6, 8 ))
    

    例如,我们使用字段的长度来确定是否设置了数字。如果在字段中设置了 5、6 或 8,则必须存在 16、32 或 128。

    10000    (Length 5, = 16)
    100000   (Length 6, = 32)
    10000000 (Length 8, = 128)
    

    只是长度本身给了我们必须设置的值。感谢你们在短短 30 分钟内解决此问题的所有帮助!

    查询在 0.23 秒内运行了超过 460,000 个字段。 :D

    【讨论】:

    • 这是一种脆弱的方法。具体来说,如果设置了第 7 位,那么长度将为 7。因此您的测试将返回 false。 不幸的是,如果设置了第 7 位,即使第 6 位 设置了,它也会返回 false - 在这种情况下,它应该返回 true。阅读本文的任何人都应该使用“位掩码”答案之一,该答案显示如何使用“&”来提取/测试所需的位。
    猜你喜欢
    • 2014-02-03
    • 2019-02-25
    • 2022-06-29
    • 2018-11-16
    • 1970-01-01
    • 2021-07-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-02
    相关资源
    最近更新 更多