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

Mik*_*sen 7 sql postgresql types boolean bit-manipulation

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

SELECT BoolA, BoolB, BoolC, BoolD FROM MyTable;
Run Code Online (Sandbox Code Playgroud)

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

例如,如果BoolA并且BoolD是真的,我想要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;
Run Code Online (Sandbox Code Playgroud)

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

Erw*_*ter 13

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

SELECT BoolD::int::bit
    || BoolC::int::bit
    || BoolB::int::bit
    || BoolA::int::bit
FROM tbl;
Run Code Online (Sandbox Code Playgroud)

TRUE转换为1,FALSE0.您可以简单地将位连接到位串.


将位(n)转换为整数

看来你需要一个integer结果 - 有一个简单快捷的方法:

SELECT (BoolD::int::bit
     || BoolC::int::bit
     || BoolB::int::bit
     || BoolA::int::bit)::bit(4)::int
FROM tbl;
Run Code Online (Sandbox Code Playgroud)

请务必阅读本手册" 位字符串函数和操作符 " 一章中的精细打印.


我想出了两个更多的想法,并组合了一个快速测试/参考与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);
Run Code Online (Sandbox Code Playgroud)

演示:

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
Run Code Online (Sandbox Code Playgroud)

您也可以使用按位OR | 而不是+运算符.对于所有五种方法,
单独的测试运行显示基本相同的性能.

  • 刚刚确认 - Npgsql会将`bit varying`转换成一个字符串,看起来像"1001"` - 所以这种方法虽然可能对某些场景有效,但并不是我想要的. (2认同)
  • 不,我不是*声称*,但是,我在提出我的建议时确实在想MySQL.因此,我最初的假设实际上是正确的.但我不确定,在Mike报告说这个想法不起作用之后,我开始认为`true`可能*可能*在PostgreSQL中转换为`-1`,而不是像MySQL那样转换为`1`.后来被证明是不正确的,所以我最终在最初的猜测中得到了重申.另一方面,如果您将整个表达式转换为"int",我认为您的想法可能适用于Mike. (2认同)