我可以将一堆布尔列转换为PostgreSQL中的单个位图吗?

时间:2012-01-29 08:25:55

标签: sql postgresql types boolean bit-manipulation

我想转换一个查询,例如:

SELECT BoolA, BoolB, BoolC, BoolD FROM MyTable;

进入位掩码,其中位由上面的值定义。

例如,如果BoolABoolD属实,我需要10019

我对以下方面的影响有所了解:

SELECT
   CASE WHEN BoolD THEN 2^0 ELSE 0 END +
   CASE WHEN BoolC THEN 2^1 ELSE 0 END +
   CASE WHEN BoolB THEN 2^2 ELSE 0 END +
   CASE WHEN BoolA THEN 2^3 ELSE 0 END
FROM MyTable;

但我不确定这是否是最好的方法,而且看起来相当冗长。有一个简单的方法吗?

3 个答案:

答案 0 :(得分:13)

对于位掩码,类型bitstring将是更好的选择。可能看起来像这样:

SELECT BoolD::int::bit
    || BoolC::int::bit
    || BoolB::int::bit
    || BoolA::int::bit
FROM tbl;

TRUE转换为1FALSE转换为0。您可以简单地将位连接到位串。


将位(n)转换为整数

似乎你需要integer作为结果 - 有一个简单的&快捷方式:

SELECT (BoolD::int::bit
     || BoolC::int::bit
     || BoolB::int::bit
     || BoolA::int::bit)::bit(4)::int
FROM tbl;

请务必阅读本手册“Bit String Functions and Operators”一章中的细则。


我想出了两个更多的想法,并将一个快速测试/参考放在一起,用10k行来总结。

测试设置:

CREATE TEMP TABLE t (boola bool, boolb bool, boolc bool, boold bool);
INSERT INTO t
SELECT random()::int::bool
     , random()::int::bool
     , random()::int::bool
     , random()::int::bool
FROM   generate_series(1,10000);

演示:

SELECT  CASE WHEN boold THEN 1 ELSE 0 END
     + (CASE WHEN boolc THEN 1 ELSE 0 END << 1)
     + (CASE WHEN boolb THEN 1 ELSE 0 END << 2)
     + (CASE WHEN boola THEN 1 ELSE 0 END << 3) AS andriy

     ,  boold::int
     + (boolc::int << 1)
     + (boolb::int << 2)
     + (boola::int << 3) AS mike

     , (boola::int::bit
     || boolb::int::bit
     || boolc::int::bit
     || boold::int::bit)::bit(4)::int AS erwin1

     ,  boold::int
     | (boolc::int << 1)
     | (boolb::int << 2)
     | (boola::int << 3) AS erwin2

     , (((
       boola::int << 1)
     | boolb::int << 1)
     | boolc::int << 1)
     | boold::int        AS erwin3
FROM   t
LIMIT  15

您也可以使用按位OR |代替+运算符 单个测试运行基本上显示所有五种方法的相同性能

答案 1 :(得分:2)

也许是这样的:

SELECT
  (CASE WHEN BoolA THEN 1 ELSE 0 END << 0) +
  (CASE WHEN BoolB THEN 1 ELSE 0 END << 1) +
  (CASE WHEN BoolC THEN 1 ELSE 0 END << 2) +
  (CASE WHEN BoolD THEN 1 ELSE 0 END << 3) AS BitMask
FROM MyTable;

其中<<bitwise shift left运算符。

答案 2 :(得分:2)

我也提出了这种方法。这是我写的自定义函数最简洁。我会接受这个答案,除非有人有更聪明的东西。

SELECT
  (BoolD::int << 0) +
  (BoolC::int << 1) +
  (BoolB::int << 2) +
  (BoolA::int << 3)
from MyTable;