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

发布于 2024-12-29 17:59:11 字数 498 浏览 2 评论 0原文

我想将查询转换为位掩码,例如:

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;

但我不确定这是否是最好的方法,而且看起来相当冗长。有没有简单的方法可以做到这一点?

I'd like to convert a query such as:

SELECT BoolA, BoolB, BoolC, BoolD FROM MyTable;

Into a bitmask, where the bits are defined by the values above.

For example, if BoolA and BoolD were true, I'd want 1001 or 9.

I have something in mind to the effect of:

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;

But I'm not sure if this is the best approach and seems rather verbose. Is there an easy way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦萦几度 2025-01-05 17:59:11

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

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

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

将 bit(n) 转换为整数

似乎您需要一个整数作为结果 - 有一个简单的 &快速方法:

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;

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

For a bitmask, the type bitstring would be the better choice. Could look like this then:

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

true converts to 1, false to 0. You can simply concatenate bits to a bitstring.

Cast bit(n) to integer

It seems you need an integer as result - there is a simple & fast way:

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

Be sure to read the fine print in the chapter "Bit String Functions and Operators" of the manual.


I came up with two more ideas and put together a quick test / reference with 10k rows to sum it all up.

Test setup:

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

Demo:

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;

You could also use | (bitwise OR) instead of the + operator.
Individual test runs show basically the same performance for all five methods.

烟火散人牵绊 2025-01-05 17:59:11

也许是这样的:

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;

其中 <<按位左移运算符。

Maybe like this:

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;

where << is the bitwise shift left operator.

疯到世界奔溃 2025-01-05 17:59:11

我也想出了这个方法。这是我能找到的最简洁的,除了编写自定义函数之外。我会接受这个答案,除非有人有更聪明的东西。

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

I came up with this approach as well. It's the most concise I could find short of writing a custom function. I'll accept this answer unless anyone has anything more clever.

SELECT
  (BoolD::int << 0) +
  (BoolC::int << 1) +
  (BoolB::int << 2) +
  (BoolA::int << 3)
from MyTable;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文