使用 SQLite 进行位掩码分组

发布于 2024-12-29 11:37:24 字数 543 浏览 1 评论 0原文

当每个表都有一个用于保存一些位掩码枚举的字段时,我有一个 sqlite 表。

我想执行一项查询,该查询将返回所有结果并将所有枚举分组到一个字段中:

Services: TEXT name,INTEGER service,INTEGER mask

SELECT service,XXX FROM Services GROUP BY service

基本上,我希望 XXX 是所有掩码的位掩码 OR (|) 的结果根据该服务。

数据:

'a1',1,1
'a2',1,2,
'a3',1,4,
'a4',1,8,

'b1',2,1,
'b2',2,3,
'b3',2,2

因此,我想得到以下行:

1,15 (1|2|4|8)
2,3 (1|3|2)

谢谢

编辑: 在我原来的问题中,我忘记提及每个掩码不是单个位,而是可以是多个位的掩码(我更改了第二个示例以反映这一点)。

I have an sqlite table when each table has a field which I use to hold some bitmask enum.

I would like to perform a query which will return me all results and group all enums into one field:

Services: TEXT name,INTEGER service,INTEGER mask

SELECT service,XXX FROM Services GROUP BY service

Basically, I would like XXX to be the result of bitmask OR (|) of all masks per that service.

Data:

'a1',1,1
'a2',1,2,
'a3',1,4,
'a4',1,8,

'b1',2,1,
'b2',2,3,
'b3',2,2

So as a result, I would like to get the following rows:

1,15 (1|2|4|8)
2,3 (1|3|2)

Thanks

EDIT:
In my original question, I've forgot to mention that each mask is not a single bit but can be a mask of multiple bits (I've changed the second example to reflect that).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

甜宝宝 2025-01-05 11:37:24

SQLite支持自定义聚合函数;根据您的设置,您可以注册自定义函数来轻松完成此操作。使用 C API:

void bitwise_or_step(sqlite3_context *context, int argc, sqlite3_value** argv)
{
    int *buffer = (int *)sqlite3_aggregate_context(context, sizeof(int));
    int x = sqlite3_value_int(argv[0]);
    *buffer |= x;
}

void bitwise_or_final(sqlite3_context *context)
{
    int *buffer = (int *)sqlite3_aggregate_context(context, sizeof(int));
    sqlite3_result_int(context, *buffer);
}

sqlite3_create_function_v2(db, "BITWISE_OR", 1, SQLITE_ANY, NULL,
    NULL, bitwise_or_step, bitwise_or_final, NULL);

然后在 SQL 中,您应该能够执行以下操作:

SELECT service,BITWISE_OR(mask) FROM Services GROUP BY service

如果您使用 PHP,则可以 也从 PHP 定义自定义聚合函数

SQLite supports custom aggregate functions; depending on your set up you could register a custom function to do this pretty easily. Using the C API:

void bitwise_or_step(sqlite3_context *context, int argc, sqlite3_value** argv)
{
    int *buffer = (int *)sqlite3_aggregate_context(context, sizeof(int));
    int x = sqlite3_value_int(argv[0]);
    *buffer |= x;
}

void bitwise_or_final(sqlite3_context *context)
{
    int *buffer = (int *)sqlite3_aggregate_context(context, sizeof(int));
    sqlite3_result_int(context, *buffer);
}

sqlite3_create_function_v2(db, "BITWISE_OR", 1, SQLITE_ANY, NULL,
    NULL, bitwise_or_step, bitwise_or_final, NULL);

Then within your SQL, you should be able to do:

SELECT service,BITWISE_OR(mask) FROM Services GROUP BY service

If you're using PHP, you can define a custom aggregate function from PHP, too.

︶葆Ⅱㄣ 2025-01-05 11:37:24

SQL 中整数的位掩码 OR (|) 操作很简单,就是将每个键的 2 个值的唯一幂相加:

todd$ sqlite3 ex1
SQLite version 3.7.5
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> create table Services(Name varchar(100), Service int, mask int);
sqlite> insert into Services values("a1", 1, 1);
sqlite> insert into Services values("a2", 1, 2);
sqlite> insert into Services values("a3", 1, 4);
sqlite> insert into Services values("a4", 1, 8);
sqlite> insert into Services values("b1", 2, 1);
sqlite> insert into Services values("b2", 2, 3);
sqlite> insert into Services values("b3", 2, 2);
sqlite> select * from Services;
a1|1|1
a2|1|2
a3|1|4
a4|1|8
b1|2|1
b2|2|3
b3|2|2

编辑:当您知道位图域时,您可以将值按位和求和:

sqlite> select Service, max(mask&1) + max(mask&2) +  max(mask&4) + max(mask&8) from Services group by Service;
1|15
2|3
sqlite> 

您可以扩展max(mask&bit) 逻辑,用于存储在位图掩码中的所有已知 2 的幂。

A bitmask OR (|) operation of integers in SQL is simple matter of summing up unique power of 2 values for each key:

todd$ sqlite3 ex1
SQLite version 3.7.5
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> create table Services(Name varchar(100), Service int, mask int);
sqlite> insert into Services values("a1", 1, 1);
sqlite> insert into Services values("a2", 1, 2);
sqlite> insert into Services values("a3", 1, 4);
sqlite> insert into Services values("a4", 1, 8);
sqlite> insert into Services values("b1", 2, 1);
sqlite> insert into Services values("b2", 2, 3);
sqlite> insert into Services values("b3", 2, 2);
sqlite> select * from Services;
a1|1|1
a2|1|2
a3|1|4
a4|1|8
b1|2|1
b2|2|3
b3|2|2

EDIT: When you know the bitmap domain, you can bitand the value into its parts and sum:

sqlite> select Service, max(mask&1) + max(mask&2) +  max(mask&4) + max(mask&8) from Services group by Service;
1|15
2|3
sqlite> 

You can extend the max(mask&bit) logic for all know powers of 2 you are storing in the bitmap mask.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文