转换"总结标志"回到原来的意思

时间:2015-12-27 18:31:18

标签: sql postgresql flags

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

这些类型分配了以下数字:

column    |   a       b       c
----------+----------------------
new       |   3       12      48
removed   |   2       8       32
changed   |   1       4       16

change列的内容是所有应用更改类型的总和,即列achangedb removedchange列为1 + 8 = 9。 (总是有变化,即可以有1个,2个或3个加数。)

我的问题:我无法想出一种聪明的方法来转换这个"总结旗帜"回到原来的意思(问题的一部分是不知道谷歌的用途)。

我可以说,如果change不均衡,a可能是newchanged;如果change>=48cnew加上可能的其他更改,则change>=32 => c removed加上可能还有其他更改,等等。我可以将它们整合到一个巨大的逻辑查询中 - 但我确信必须有一个复杂的解决方案才能做到这一点。

我使用PostgreSQL以防相关。该表有大约5000万行。

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

这可以通过使用逐位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;

这是fiddle

示例输出:

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

这是另一种方法。这还会返回3个额外的列,但每种类型的更改一个,并且值是' a',''' c'的串联。

select  *,
        concat(
          case when change        & 3 = 1 then 'a' end,
          case when (change >> 2) & 3 = 1 then 'b' end, 
          case when (change >> 4) & 3 = 1 then 'c' end) changed,
        concat(
          case when change        & 3 = 2 then 'a' end,
          case when (change >> 2) & 3 = 2 then 'b' end, 
          case when (change >> 4) & 3 = 2 then 'c' end) removed,
        concat(
          case when change        & 3 = 3 then 'a' end,
          case when (change >> 2) & 3 = 3 then 'b' end, 
          case when (change >> 4) & 3 = 3 then 'c' end) new
from    mytable;

这是fiddle

示例输出:

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)