测试是否在用于MySQL查询的SET类型字段中打开给定集中的所有值

时间:2012-04-16 09:55:30

标签: mysql query-optimization bit-manipulation

我没有在MySQL查询中看到一种清晰简单的方法。架构看起来像:

CREATE TABLE users (
    id VARCHAR(20),
    col SET('read', 'write', 'edit', 'delete'),
);

如果我想查询具有readwrite privs的所有用户(无论其他任何值设置如何),我提出的获取行的唯一查询是:

SELECT id, privs
FROM users WHERE
FIND_IN_SET('read',privs) > 0 AND 
FIND_IN_SET('write',privs) > 0

有没有办法简化这个?类似的东西:

SELECT id, privs
FROM users WHERE
privs('read' & 'write')

假设我想使用更复杂的位逻辑,但我想知道在使用SET类型时,工作示例是否是实现此目的的唯一方法。

2 个答案:

答案 0 :(得分:1)

您的值以与create table语句相同的顺序存储。

在你的情况下:

        decimal   |   binary
read    1         |   0001
write   2         |   0010
edit    4         |   0100
delete  8         |   1000

您可以通过添加0来“转换”您的列来获取小数值。

所以为了得到阅读和写作你可以这样做:

SELECT id, privs
FROM users 
WHERE
privs+0 = 3;

详细了解here.

更新:

privs+0 = 3只会返回“read& write”。

就像我说的那样,无论值多长时间分配给一个条目,值都会按顺序存储。

所以你也可以这样做:

SELECT id, privs
FROM users 
WHERE
privs = 'read,write';

如果你想至少阅读&写作可能更多:

SELECT id, privs
FROM users 
WHERE
privs LIKE 'read,write%';

答案 1 :(得分:1)

如果在MySQL中没有优雅的方法,我会解决这个问题,至少我不需要手动记住所有设置元素的位字段位置/值,我仍然可以使用更多的助记符字符串。只使用CROSS JOIN:

SELECT u.id, u.col
FROM users u

CROSS JOIN
(
  select sum(val) as bit_result from
  (
  SELECT 'read' as txt,1 as val
  union
  SELECT 'write' as txt,2 as val
  union
  SELECT 'edit' as txt,4 as val
  union
  SELECT 'delete' as txt,8 as val
  ) as x
  where txt in ('read','write')
) as z

WHERE u.col & z.bit_result = z.bit_result

源数据:

CREATE TABLE users (
    id VARCHAR(20),
    col SET('read', 'write', 'edit', 'delete')
);

insert into users(id,col)
values ('hello','read,write');

insert into users(id,col)
values ('hola','read,delete,write');

insert into users(id,col)
values ('yeah','delete,write');

输出:'hello'和'hola'

http://sqlfiddle.com/#!2/56070/41