Sql 转换;总结旗帜“;回归本义

Sql 转换;总结旗帜“;回归本义,sql,postgresql,flags,Sql,Postgresql,Flags,我必须使用一个数据库,其中包含一列change,指示与前一个相应条目相比,其他三列的更改方式。更改类型可以是new、removed或changed 这些类型分配了以下编号: column | a b c ----------+---------------------- new | 3 12 48 removed | 2 8 32 changed | 1 4 1

我必须使用一个数据库,其中包含一列
change
,指示与前一个相应条目相比,其他三列的更改方式。更改类型可以是
new
removed
changed

这些类型分配了以下编号:

column    |   a       b       c
----------+----------------------
new       |   3       12      48
removed   |   2       8       32
changed   |   1       4       16
change
列的内容是所有应用更改类型的总和,即,如果列
a
change
b
删除,则
change
列将为1+8=9。(总是有变化,即可以有1、2或3个总和。)

我的问题是:我想不出一个聪明的方法来将这个“汇总标志”转换回它的原始含义(部分问题是不知道谷歌要做什么)

我可以看出,如果
change
是不均匀的,
a
要么是
new
要么是
changed
;如果
change>=48
c
new
加上可能的其他更改,否则
change>=32
=>c被
删除
加上可能的其他更改,依此类推。我可能会把它们放在一个巨大的逻辑查询中——但我相信一定有一个复杂的解决方案可以做到这一点


如果相关的话,我会使用PostgreSQL。该表大约有5000万行。

您可以使用位操作。如果我理解正确:

select (case when col::bit(8) & B'00000011' then 'new'
             when col::bit(8) & B'00000001' then 'changed'
             when col::bit(8) & B'00000010' then 'removed'
        end) as a_status,
       (case when col::bit(8) & B'00001100' then 'new'
             when col::bit(8) & B'00000100' then 'changed'
             when col::bit(8) & B'00001000' then 'removed'
        end) as b_status,
       (case when col::bit(8) & B'00110000' then 'new'
             when col::bit(8) & B'00010000' then 'changed'
             when col::bit(8) & B'00100000' then 'removed'
        end) as c_status

这可以通过将位AND运算符(
&
)与位移位(
>
)结合使用来实现

以下查询返回表的所有记录,并在另外三列中分别更改为a、b和c:

select  *,
        case change & 3 
             when 1 then 'changed'
             when 2 then 'removed'
             when 3 then 'new'
        end as change_to_a,
        case (change >> 2) & 3 
             when 1 then 'changed'
             when 2 then 'removed'
             when 3 then 'new'
        end as change_to_b,
        case (change >> 4) & 3 
             when 1 then 'changed'
             when 2 then 'removed'
             when 3 then 'new'
        end as change_to_c
from    mytable;
这是一本书

示例输出:

id  change  change_to_a change_to_b change_to_c
-----------------------------------------------
1     9       changed     removed     (null)
2    50       removed     (null)        new
3    83         new       (null)      changed
4    20        (null)     changed     changed
5    25       changed     removed     changed
id  change  changed     removed    new
-----------------------------------------
1     9        a            b     (null)
2    50     (null)          a       c
3    83        c         (null)     a
4    20       bc         (null)   (null)
5    25       ac            b     (null)
这是另一种方法。这还会返回3个额外的列,但每种更改类型一个,并且这些值是“a”、“b”、“c”的串联:

这是一本书

示例输出:

id  change  change_to_a change_to_b change_to_c
-----------------------------------------------
1     9       changed     removed     (null)
2    50       removed     (null)        new
3    83         new       (null)      changed
4    20        (null)     changed     changed
5    25       changed     removed     changed
id  change  changed     removed    new
-----------------------------------------
1     9        a            b     (null)
2    50     (null)          a       c
3    83        c         (null)     a
4    20       bc         (null)   (null)
5    25       ac            b     (null)

非常感谢,它工作得很好。您是如何知道使用
&
的,每个都有3个,而
>
有些则有2个或4个?试错?逻辑?一旦你有了它,这是有道理的,但要做到这一点很难……这是逻辑。正如你所知道的,对于b和a,数字乘以4,然后再乘以4,得到c的情况。现在除以四等于移动2个二进制数字[这是我(老)年纪的程序员都知道的]。AND运算符是提取某些位的一种方法。数字3对应于数字的较低2位,其值可以为0-3。这当然是逻辑,当你掌握二进制,掩蔽和移位时,它会帮助你很多。啊,好的,我明白了。年轻的程序员在这里,仍然有很多东西需要学习,尤其是在这个抽象的层次上。我以前听说过bit-wise操作,但到目前为止从未真正使用过。再次感谢,回答得很好!我没有让你的工作……:/Postgres不想对整数使用
&
,我无法正确地将
changed
转换为bin或找到
dectobin
函数。。。这是一个遗憾,因为我真的很好奇你是如何解决这个问题的,而没有像trincot那样进行一点明智的转换。@user3746543。如果
col
是整数,则可以将其转换为操作的
bit()
类型。