2012-12-04 20 views
4

我有一個變化的位掩碼字段,我想對它執行按位與操作。PostgreSQL位變量的位運算符「不能和不同大小的位字符串」

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') 

(你需要有不同的長度位掩碼在表中得到這個錯誤。)

我期待的按位數學看起來像下面這樣: 100000010 = 00010

我也嘗試將位掩碼投射到一個沒有運氣的整數。

爲什麼PostgreSQL會窒息?

我應該如何重寫這個查詢來很好地播放?

我可以使用以下方法來獲取位運算符的工作: LPAD(read_roles_bitmask :: VARCHAR,64, '0'):: BIGINT

但是這僅限於64位,有沒有更好的辦法?

+0

這是一個奇怪的限制。我希望Pg的'&'可以自動向零擴展小操作數。 –

+0

@克雷格:「必須是相同的大小」的行爲被記錄在案。另外,'B'10':: bit(1)'是'B'1'','B'1':: bit(2)'是'B'10'',因此位從左到右。我覺得位順序在某個位置發生了變化,所以他們可能會強迫你明確地避免版本問題。 –

+0

它被記錄下來,但坦率地說,右位擴展位域並沒有隱含或明確地提供左延伸選項是沒用的。誰使用從左到右的位串? –

回答

6

PostgreSQL bitbit varying類型的行爲極其無用,它拒絕擴展操作的位域,並且將它們右移擴展而不是左移擴展它們。

對於Pg而言,在AND或OR操作之前用零向左延伸較小的操作數是有意義的,而不是失敗。

不能使用強制轉換爲bit(n)得到同樣的長度,因爲某種原因瘋狂強制轉換爲bit(n)右墊的說法,使得它在幾乎所有情況下沒用。

你可以使用類似lpad($1::text, greatest(length($1), length($2)),'0')::bit varying的東西來向左延伸一個位爲零的字段爲兩個長度中較大的一個。這很麻煩,但它會起作用。我建議編寫包裝函數來包含混亂。

或者,考慮修改src/backend/utils/adt/varbit.c中的bit支持代碼,以向左延伸位和左截斷位字段添加函數,並執行左向延伸比較的函數。根據現有的代碼應該很容易。

1

今天我有類似的問題。我想要做幾乎同樣的事情:屏蔽掉一個比特串的至少顯著兩位並將結果與​​文字值進行比較,就像這樣:

status & b'11' > b'01' 

(狀態是我有點不同的列)。

起初我試圖使用克雷格的解決方案,但它得到了相當混亂很快,因爲不僅面具就必須被延長,所以做我的結果與比較值,根據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提取位的任意一組進行比較。