我有一个不同的位掩码字段,我想对它执行按位AND。
PG::Error: ERROR: cannot AND bit strings of different sizes
SELECT "groups".* FROM "groups" WHERE (read_roles_bitmask = B'0' OR read_roles_bitmask & B'10' > B'0')
(你需要在表中使用不同长度的位掩码来获得此错误。)
我期待按位数学看起来如下: 00010& 100000010 = 00010
我也尝试将位掩码转换为整数而没有运气。
为什么PostgreSQL会扼杀这个?
我该怎样重写这个查询才能很好地玩?
我能够使用以下方法让按位运算符工作: LPAD(read_roles_bitmask :: VARCHAR,64, '0'):: BIGINT
然而,这仅限于64位,有更好的方法吗?
答案 0 :(得分:6)
PostgreSQL bit
和bit varying
类型的行为非常无用,它拒绝扩展操作的位域的方式,并且它正确地扩展它们用于强制转换而不是向左扩展它们。
Pg在AND或OR运算之前用零加左延伸较小的操作数是有意义的,而不是失败。
你不能使用强制转换来bit(n)
来获得相同的长度,因为出于某种疯狂的原因,强制转换为bit(n)
右键填充参数,几乎在所有情况下都没用。
您可以使用lpad($1::text, greatest(length($1), length($2)),'0')::bit varying
之类的内容向左扩展一个带有零的位字段到两个长度中的较大者。这很麻烦,但它会起作用。我建议编写包装器函数以包含混乱。
或者,考虑修改bit
中的src/backend/utils/adt/varbit.c
支持代码以向左扩展和左截断位字段添加函数,并使用函数进行左扩展比较。根据现有代码,这应该很容易。
答案 1 :(得分:1)
今天我遇到了类似的问题。我想做几乎完全相同的事情:屏蔽位串的最低两位并将结果与文字值进行比较,如下所示:
status & b'11' > b'01'
(状态是我的位变化列。)
最初我尝试使用Craig的解决方案,但它很快就变得非常混乱,因为不仅需要扩展掩码,我将比较结果的值也是如此,因为根据postgresql:
t2=> select b'0010' < b'01';
?column?
----------
t
(1 row)
在应用<
操作之前,RHS正确填充以使其与LHS相同。
最后我解决了这个问题:
(status << length(status)-2)::bit(2) > b'01'
关于这一点的好处是它允许您提取任何位集以进行比较。例如,从左侧获取第3位:
(status << length(status)-6)::bit(2)
您还可以使用substring
提取任意位集以进行比较。
答案 2 :(得分:0)
1),如其他答案中所述-
qscintillaWidget.setCaretLineVisible(True)
qscintillaWidget.setCaretLineBackgroundColor(QtGui.QColor('lightblue'))
2)一种解决方法是-
postgres has has some inconvenient/counterintuitive behaviors -
right padding when casting to bit(n),
bitwise ops only on similar size,
etc.
优点:
double-casting every value - to integer and then to bit(XX)
示例:
基本左填充:
- left vs right padding works correctly
- all the bit-strings have same length for correct bitwise operations
- comparisons work correctly
- bit-masking/casting to get least significant bits
按位操作:
select B'0010'::int::bit(22)
0000000000000000000010
比较:
select B'0010'::int::bit(22) | B'01'::int::bit(22)
0000000000000000000011
位屏蔽/广播以获得三个最低有效位:
select B'0010'::int::bit(22) > B'01'::int::bit(22)
true
位屏蔽/广播以获得三个MOST有效位:
select B'11010'::int::bit(3)
010
更新: 使用int8容纳更长的位字符串