我想转换一个查询,例如:
SELECT BoolA, BoolB, BoolC, BoolD FROM MyTable;
进入位掩码,其中位由上面的值定义。
例如,如果BoolA
和BoolD
属实,我需要1001
或9
。
我对以下方面的影响有所了解:
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;
但我不确定这是否是最好的方法,而且看起来相当冗长。有一个简单的方法吗?
答案 0 :(得分:13)
对于位掩码,类型bitstring
将是更好的选择。可能看起来像这样:
SELECT BoolD::int::bit
|| BoolC::int::bit
|| BoolB::int::bit
|| BoolA::int::bit
FROM tbl;
TRUE
转换为1
,FALSE
转换为0
。您可以简单地将位连接到位串。
似乎你需要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;