【问题标题】:SQL select default value only if specific value does not exist仅当特定值不存在时 SQL 才选择默认值
【发布时间】:2015-10-19 14:25:47
【问题描述】:

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

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

数据表:

 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

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

【问题讨论】:

    标签: sql oracle


    【解决方案1】:

    这可能最好通过相关子查询来完成。在 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;
    

    也就是说,获取具有最少“All”值的匹配项。

    在早期版本的 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() 进行排名。

    【讨论】:

    • hmm 第一个建议对我不起作用,因为我不在 Oracle 12g 上,第二个建议似乎很接近,但输出有点偏,ID 2 和 3 在输出中显示 NULL acct_nums .
    • @MattO 。 . .您是否拥有ALLAll 的“所有”值?在 Oracle 中混淆大小写可能会导致问题。
    • 就是这样!我不知道我是怎么错过的。感谢您的帮助戈登!
    • @MattO 。 . .这都是我的错。我将混合大小写版本放在我的答案中。
    • Gordon - 我如何获得工作的优先权?我将在此线程的下一个答案中发布另一个示例,因为 cmets 似乎不允许格式化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-20
    • 2014-11-12
    • 1970-01-01
    • 1970-01-01
    • 2022-08-21
    • 1970-01-01
    • 2014-04-22
    相关资源
    最近更新 更多