Oracle SQL 中的复杂案例语句

Posted

技术标签:

【中文标题】Oracle SQL 中的复杂案例语句【英文标题】:Complex Case Statement in Oracle SQL 【发布时间】:2018-12-20 11:23:07 【问题描述】:

我有一个场景,我有 4 列 - SUBBRAND、COLLECTIONS、PLCYCLE、COLORFAMILY,我必须为记录分配优先级:

    如果所有 4 个都有有效值(非空白或非空) - 优先级 '1' ; 如果其中任何 3 个具有有效值(非空白或非空) - 优先级 '2' ; 如果其中任何 2 个具有有效值(非空白或非空) - 优先级 '3' ; 如果其中任何 1 个具有有效值(非空白或非空) - 优先级 '4'。

编写包含所有可能组合的案例语句是完成此任务的唯一方法还是有任何简单的方法?

示例代码:

CASE WHEN SUBBRAND IS NOT NULL AND COLLECTIONS IS NOT NULL 
     AND PLCYCLE IS NOT NULL AND COLORFAMILY  IS NOT NULL
     THEN 1 AS PRIORITY,
     WHEN SUBBRAND IS NOT NULL AND COLLECTIONS IS NOT NULL 
     AND PLCYCLE IS NOT NULL OR
     WHEN COLLECTIONS IS NOT NULL AND PLCYCLE IS NOT NULL 
     AND COLORFAMILY IS NOT NULL OR
     WHEN PLCYCLE IS NOT NULL AND COLORFAMILY IS NOT NULL
     AND WHEN SUBBRAND IS NOT NULL OR
     so on....
     THEN 2 AS PRIORITY
     and other conditions..
END PRIORITY

提前感谢您的帮助!

【问题讨论】:

如果全部为空怎么办?草稿中每个条件后面的 OR 是无效的语法。您的方法可能优于任何复杂的 UNION 和聚合方法,因为未计算列上的 CASE 尽可能便宜。 【参考方案1】:

在Oracle 中,空字符串值被视为NULL,因此您只需检查NULL。 如果NULL1 否则使用NVL2 生成0

SELECT 
  5 - ( 
  NVL2(SUBBRAND, 1, 0) + 
  NVL2(COLLECTIONS, 1, 0) + 
  NVL2(PLCYCLE, 1, 0) + 
  NVL2(COLORFAMILY, 1, 0) 
  ) AS Priority

我猜不存在所有 4 列都为 NULL 的情况。

【讨论】:

大家好 .. 感谢您抽出宝贵时间回答 :) 没有有效的商业案例,所有四列都为 NULL;我的意思是,企业根本不认为这种情况是有效的。并且优先级值是根据非 NULL 的列数固定的。这有帮助吗? 如果表中设置了针对这种情况的约束,则没有问题。 不,我们对这些列的表没有任何约束。字段(列)由用户维护,他们可以选择将值填充到这些列中或将它们留空。如果所有 4 个都是空的,我们必须忽略相应的记录。任务是检查有效列的组合并为其分配默认优先级;就像所有 4 中都有任何值一样,相应的记录将优先级分配为 1,任何 3,然后优先级为 2,依此类推.. 我们必须忽略相应的记录这意味着您会处理无效的行,所以没关系,否则如果优先级为 5,则忽略。跨度> 是的,你是对的。我们必须包含一个条件来处理无效行但不分配任何优先级。【参考方案2】:

也许首先计算 NULL 值:

SELECT 1 /* highest priority */ + 
       /* increase priority for each non-empty value */ 
       + NVL2(SUBBRAND, 0, 1) + NVL2(COLLECTIONS, 0, 1) + NVL2(PLCYCLE, 0, 1) + NVL2(COLORFAMILY, 0, 1) 
  AS PRIORITY
...

正如 dlatikay 注意到的那样:如果所有值都为空,您必须决定怎么办。在上述解决方案中,优先级将变为 5,这是您想要的吗?

【讨论】:

【参考方案3】:

NVL2() 如果空白表示没有字符,则很方便。但是,如果“空白”允许空格或其他字符,则需要case 逻辑。我会去:

SELECT (1 +
        NVL2(TRIM(' ' FROM SUBBRAND), 0, 1) + 
        NVL2(TRIM(' ' FROM COLLECTIONS), 0, 1) + 
        NVL2(TRIM(' ' FROM PLCYCLE), 0, 1) + 
        NVL2(TRIM(' ' FROM COLORFAMILY), 0, 1) 
       ) AS Priority

【讨论】:

【参考方案4】:

发布对我有用的最终代码(有点)。 感谢大家的帮助,非常感谢 forpas 的所有帮助:))

SELECT U, V, W, X, Y, Z, SUBBRAND, COLLECTIONS, PLCYCLE, COLORFAMILY,  
  CASE 
       WHEN ABC = 1
       THEN (SELECT MAX (5 /* highest priority */ + 
             /* increase priority for each non-empty value */ 
             + NVL2(SUBBRAND, 0, 1) + NVL2(COLLECTIONS, 0, 1) + NVL2(PLCYCLE, 0, 1) + 
             NVL2(COLORFAMILY, 0, 1)) PRIORITY
               FROM T1) 
       WHEN ABC = 0
       THEN (SELECT MAX (9 /* highest priority */ + 
             /* increase priority for each non-empty value */ 
             + NVL2(SUBBRAND, 0, 1) + NVL2(COLLECTIONS, 0, 1) + NVL2(PLCYCLE, 0, 1) + 
             NVL2(COLORFAMILY, 0, 1)) PRIORITY
               FROM T1)
  END PRIORITY, ABC
FROM T1
WHERE NVL2(SUBBRAND, 1, 0) + NVL2(COLLECTIONS, 1, 0) + NVL2(PLCYCLE, 1, 0) + 
      NVL2(COLORFAMILY, 1, 0) > 0;

如果可以建议对此查询进行任何性能调整,那将非常有帮助:D 数据量大约为 100 M 或更多。

【讨论】:

以上是关于Oracle SQL 中的复杂案例语句的主要内容,如果未能解决你的问题,请参考以下文章

Oracle SQL:案例语句

常用sql语句及案例(oracle)

Oracle SQL - 动态案例语句

经典案例:如何优化Oracle使用DBlink的SQL语句

常用sql语句及案例(oracle)

常用sql语句及案例(oracle)