仅当特定值不存在时,SQL才会选择默认值

时间:2015-07-28 20:23:24

标签: sql oracle

我正在尝试基于多个列连接2个表,但是如果任何给定列不存在特定值,则希望从默认行返回结果。

以下是我要加入的2个表的示例:

DATA_TABLE:

 ID      CATEGORY_1          CATEGORY_2         CATEGORY_3
 1           Y                   Y                  Y 
 2           Y                   N                  N 
 3           Y                   N                  Y 

ACCOUNT_TABLE:

 CATEGORY_1       CATEGORY_2     CATEGORY_3     ACCT_NUM
     Y                Y              Y            123
     Y                N              ALL          234
     ALL              ALL            Y            345

我想要实现的是,如果数据在CATEGORY_1,2和3上匹配,则选择ACCOUNT_TABLE.ACCT_NUM,但如果不匹配,则选择与ACCOUNT_TABLE中的“ALL”值关联的ACCT_NUM。此外,如果由于ACCOUNT_TABLE中的“ALL”值而找到多个记录,我想根据优先级返回ACCT_NUM(即CATEGORY_1上的匹配优先于CATEGORY_2上的匹配)。

到目前为止,我写的查询如下:

 select d.*, a.acct_num from data_table d, account_table a
  where d.category_1 = DECODE(a.category_1,'ALL',d.category_1,a.category_1)
  and d.category_2 = DECODE(a.category_2,'ALL',d.category_2,a.category_2)
  and d.category_3 = DECODE(a.category_3,'ALL',d.category_3,a.category_3)

但我的输出看起来像这样:

 ID    CATEGORY_1       CATEGORY_2     CATEGORY_3     ACCT_NUM
 1         Y                Y              Y            123
 1         Y                Y              Y            345
 2         Y                N              N            234
 3         Y                N              Y            234
 3         Y                N              Y            345

对于ID 1,我只想要返回ACCT_NUM 123,因为类别1,2和3上的匹配应该优先于“ALL”记录。

ID 2正确匹配并返回预期的ACCT_NUM。

ID 3我想返回ACCT_NUM 234,因为类别1 + 2上的匹配应该优先于类别3上的匹配。

以下是我的预期输出:

 ID    CATEGORY_1       CATEGORY_2     CATEGORY_3     ACCT_NUM
 1         Y                Y              Y            123
 2         Y                N              N            234
 3         Y                N              Y            234

有关如何编写查询以实现上述目的的任何帮助/建议吗?

1 个答案:

答案 0 :(得分:2)

最好使用相关子查询来完成。在Oracle 12g中,您可以这样做:

select d.*,
       (select a.acct_num
        from account_table a
        where (d.category_1 = a.category_1 or a.category_1 = 'ALL') and
              (d.category_2 = a.category_2 or a.category_2 = 'ALL') and
              (d.category_3 = a.category_3 or a.category_3 = 'ALL')
        order by ((case when a.category_1 = 'ALL' then 1 else 0 end) +
                  (case when a.category_2 = 'ALL' then 1 else 0 end) +
                  (case when a.category_3 = 'ALL' then 1 else 0 end)
                 ) asc
        fetch first 1 row only
       ) as acct_num       
from data_table d;

即,使用最少的“全部”值获取匹配。

在早期版本的Oracle中,您可以使用聚合和keep

执行相同的操作
select d.*,
       (select max(a.acct_num) keep (dense_rank first
                                     order by ((case when a.category_1 = 'ALL' then 1 else 0 end) +
                                               (case when a.category_2 = 'ALL' then 1 else 0 end) +
                                               (case when a.category_3 = 'ALL' then 1 else 0 end)
                                              ) asc
                                     )
        from account_table a
        where (d.category_1 = a.category_1 or a.category_1 = 'ALL') and
              (d.category_2 = a.category_2 or a.category_2 = 'ALL') and
              (d.category_3 = a.category_3 or a.category_3 = 'ALL')

       ) as acct_num       
from data_table d;

您也可以使用join执行类似操作,然后使用row_number()进行排名。