我必须使用包含列change
的数据库,指示在与先前相应条目的比较中,其他三个列的更改方式。更改类型可以是new
,removed
或changed
。
这些类型分配了以下数字:
column | a b c
----------+----------------------
new | 3 12 48
removed | 2 8 32
changed | 1 4 16
change
列的内容是所有应用更改类型的总和,即列a
是changed
和b
removed
, change
列为1 + 8 = 9。 (总是有变化,即可以有1个,2个或3个加数。)
我的问题:我无法想出一种聪明的方法来转换这个"总结旗帜"回到原来的意思(问题的一部分是不知道谷歌的用途)。
我可以说,如果change
不均衡,a
可能是new
或changed
;如果change>=48
,c
为new
加上可能的其他更改,则change>=32
=> c
removed
加上可能还有其他更改,等等。我可以将它们整合到一个巨大的逻辑查询中 - 但我确信必须有一个复杂的解决方案才能做到这一点。
我使用PostgreSQL以防相关。该表有大约5000万行。
答案 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)