在JOIN子句中使用BITAND

时间:2016-01-06 21:48:52

标签: oracle oracle11g

我希望在BITAND中使用JOIN来对记录进行分类。

此查询正确地将器官分组:

WITH

data AS (
  select 2 bits, 'LUNG [2]' organs from dual
  union all
  select 18  bits, 'LUNG [2]; KIDNEY [16]' organs from dual
  union all
  select 64 bits, 'HEART [64]' organs from dual
  union all
  select 66 bits, 'LUNG [2]; HEART [64]' organs from dual
)

select  *
        ,case when BITAND(bits,2)=2 OR BITAND(bits,66)=66 then 'Y' end LUNG_YN
        ,case when BITAND(bits,16)=16 or BITAND(bits,4)=4 then 'Y' end KIDNEY_YN
        ,case when BITAND(bits,64)=64 AND not BITAND(bits,2)=2 then 'Y' end HEART_YN
from    data

结果:

BITS    ORGANS                  LUNG_YN KIDNEY_YN   HEART_YN
2       LUNG [2]                Y   
18      LUNG [2]; KIDNEY [16]   Y       Y   
64      HEART [64]                                  Y
66      LUNG [2]; HEART [64]    Y*

(*肺/心脏组合被企业视为'肺';不要问)

但是,我还需要将每个器官记录放入多个桶中:

BITS    ORGANS                  BUCKET
2       LUNG [2]                LUNG [2]
18      LUNG [2]; KIDNEY [16]   LUNG [2]
18      LUNG [2]; KIDNEY [16]   KIDNEY [16]
64      HEART [64]              HEART [64]
66      LUNG [2]; HEART [64]    LUNG [2]

为了生成这个,我正在使用:

-- referencing earlier data table

p as (
  select 2 BITS, 'LUNG [2]' BUCKET from dual
  union all
  select 16 BITS, 'KIDNEY [16]' BUCKET from dual
  union all
  select 64 BITS, 'HEART [64]' BUCKET from dual
)

select  data.* 
        ,p.*
from    data
inner join p on BITAND(data.bits,p.bits)=p.bits
order by data.bits, p.bits

不幸的是,这导致了额外的分配(最后一行):

BITS    ORGANS                  BUCKET
2       LUNG [2]                LUNG [2]
18      LUNG [2]; KIDNEY [16]   LUNG [2]
18      LUNG [2]; KIDNEY [16]   KIDNEY [16]
64      HEART [64]              HEART [64]
66      LUNG [2]; HEART [64]    LUNG [2]
66      LUNG [2]; HEART [64]    HEART [64] (*erroneous*)

**编辑**

我限制器官组合以简化问题。因此,我不能简单地列出p中的所有按位组合 - 它确实需要“更聪明”。

** /编辑**

有没有办法构建BITAND中的JOIN(或p中的值)以使查询以所需方式运行?

2 个答案:

答案 0 :(得分:1)

明确询问该商家如何映射BUCKET

答案将是这样的

create table map_bucket as
WITH map_bucket AS (
  select 2 bits, 'LUNG [2]' BUCKET from dual
  union all
  select 18  bits, 'LUNG [2]' BUCKET from dual
  union all
  select 18  bits, 'KIDNEY [16]' BUCKET from dual
  union all  
  select 64 bits, 'HEART [64]' BUCKET from dual
  union all
  select 66 bits, 'LUNG [2]' BUCKET from dual
)
select * from map_bucket
;

在重新生成查询中使用此映射表:

WITH data AS (
  select 2 bits, 'LUNG [2]' organs from dual
  union all
  select 18  bits, 'LUNG [2]; KIDNEY [16]' organs from dual
  union all
  select 64 bits, 'HEART [64]' organs from dual
  union all
  select 66 bits, 'LUNG [2]; HEART [64]' organs from dual
) 
select  data.*, 
        p.*
from    data
inner join map_bucket p on data.bits=p.bits
order by data.bits, p.bits
;

按预期结果:

     BITS ORGANS                      BITS BUCKET    
---------- --------------------- ---------- -----------
         2 LUNG [2]                       2 LUNG [2]    
        18 LUNG [2]; KIDNEY [16]         18 LUNG [2]    
        18 LUNG [2]; KIDNEY [16]         18 KIDNEY [16] 
        64 HEART [64]                    64 HEART [64]  
        66 LUNG [2]; HEART [64]          66 LUNG [2]

或者,如果您只需要消除少数例外,可以在连接条件中简单地添加它们:

select  data.* 
        ,p.*
from    data
inner join p on BITAND(data.bits,p.bits)=p.bits
and /* suppress exception here - lung & hearts count as lung only  */ 
(data.bits != 66 or p.bits = 2)
order by data.bits, p.bits
;

答案 1 :(得分:0)

找到了解决方案。

此查询:

select  data.* 
        ,p.*
from    data
inner join p ON 
        (bitand(data.bits,2)=p.bits OR bitand(data.bits,66)=p.bits) OR
        (bitand(data.bits,16)=p.bits) 
order by tt.bits, p.bits

产生所需的结果:

BITS    ORGANS                  BUCKET
2       LUNG [2]                LUNG [2]
18      LUNG [2]; KIDNEY [16]   LUNG [2]
18      LUNG [2]; KIDNEY [16]   KIDNEY [16]
64      HEART [64]              HEART [64]
66      LUNG [2]; HEART [64]    LUNG [2]