Postgres 中通用位串与零的比较

2024-03-01

有没有办法在不硬编码位串宽度0的情况下进行非零位串测试?

例如,假设我有两个表,用户和功能,每个表都有掩码,我想测试一下:

SELECT u.name FROM Users u, Features f
  WHERE u.mask & f.mask;

匹配隐式非零结果。但是,SQL 需要显式布尔结果WHERE与隐式强制转换相反,如下所示:

SELECT u.name FROM Users u, Features f
  WHERE (u.mask & f.mask) != 0::BIT(2048);

我不想硬编码2048(或其他)出于多种原因在此查询中。

Testing expr = 0 or expr > 0导致类型错误。奇怪的是,我可以测试expr = 0::BIT(1),但这给出了错误的答案,因为 Postgres 并不认为所有全零位字符串都是相等的。

select 0::BIT(2) > 0::BIT(1);
 ?column? 
----------
 t
(1 row)

我可以通过这样做创建一个计算的零:

SELECT u.name FROM Users u, Features f
  WHERE (u.mask & f.mask) != (u.mask & ~u.mask);

这可行,但感觉像是一个糟糕的黑客。

有什么建议或见解吗?

RESULTS

我对下面提供的几个选项进行了基准测试。感谢您的建议,埃尔文!

基于非常大的数据集和 100,000 个查询,我发现以下构造导致每秒关联的查询数。希望 Postgres 团队的有人看到这一点并提供通用 0 来加快速度!不幸的是,大多数通用方法似乎都会产生相当昂贵的字符串转换。

Constructs                              |  Queries / s
----------------------------------------+--------------
(u.mask & f.mask) <> 0::BIT(2048)       |  158
(u.mask & f.mask) <> (u.mask # u.mask)  |  135
(u.mask & f.mask) <> (u.mask & ~u.mask) |  125
position('1' IN (u.mask & f.mask)) > 0  |   37
(u.mask & f.mask)::TEXT !~ '^0+$'       |   27

短位串

排除以下情况返回一个仅由零组成的位串,但长度可能会改变(B'000...'),您可以使用强制转换来integer (up to bit(32)) or bigint (up to bit(64)):

SELECT u.name
FROM   users u
JOIN   features f ON (u.mask & f.mask)::int <> 0;

当转换为整数时,所有结果都是0.
这也排除了其中任一列是的情况NULL。换句话说,结果必须至少包含一个1.

长位串

如果您的值可能长于 64 位,您可以转换为text并用正则表达式检查:

ON (u.mask & f.mask)::text !~ '^0+$'

模式解释:

^.. 字符串的开头
0+.. 一个或多个“0”
$.. 字符串结尾

Or, as 手册告知 http://www.postgresql.org/docs/current/interactive/functions-bitstring.html:

以下 SQL 标准函数适用于位字符串以及 字符串:length, bit_length, octet_length, position, substring, overlay.

Ergo:

ON position('1' IN (u.mask & f.mask)) > 0
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Postgres 中通用位串与零的比较 的相关文章

随机推荐