admin

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

sql

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

SELECT BoolA, BoolB, BoolC, BoolD FROM MyTable;

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

例如,如果BoolABoolD为true,则我想要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;

但是我不确定这是否是最好的方法,而且看起来很冗长。是否有捷径可寻?


阅读 150

收藏
2021-05-10

共1个答案

admin

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

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

TRUE皈依1FALSE0。您可以简单地将位连接为位串。


将bit(n)转换为整数

看来您需要一个integer结果-有一个简单而快速的方法:

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

请务必阅读本手册“位字符串函数和运算符”一章中的详细说明。


我提出了另外两个想法,并结合了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

您也可以使用按位或| 而不是+运算符。
单独的测试运行 显示出这五种方法的基本 相同的性能

2021-05-10