Oracle SQL 中的最小值但不为 NULL

Posted

技术标签:

【中文标题】Oracle SQL 中的最小值但不为 NULL【英文标题】:Least value but not NULL in Oracle SQL 【发布时间】:2014-01-23 16:21:29 【问题描述】:

我想在我的过程中使用函数 LEAST 来找到最小值。问题是某些值可能是 NULL,所以如果我这样做

select least(NULL,0,1) from dual

我得到的答案是 NULL,这可能是正确的,因为这不是我期望返回的。我想得到最不真实的非零值。非常感谢任何帮助。

【问题讨论】:

【参考方案1】:

如果任何参数为 NULL,则您希望取其他参数中的最小值。如果所有参数都为 NULL,则要返回 NULL。

我可能会为两个参数使用这样的东西:

LEAST(NVL(colA,colB), NVL(colB,colA))

但是,对于 >2 个参数,它开始变得丑陋:

LEAST(COALESCE(colA,colB,colC)
     ,COALESCE(colB,colA,colC)
     ,COALESCE(colC,colA,colB))

此时我会开始考虑魔法值;但这可能是错误的(例如,如果其中一个值合法地魔法值怎么办?):

SELECT CASE WHEN r = maxv THEN NULL ELSE r END AS result
FROM   (SELECT LEAST(NVL(:colA,maxv)
                    ,NVL(:colB,maxv)
                    ,NVL(:colC,maxv)) AS r, maxv
        FROM   (SELECT 9.999999999999999999999999999999999999999e125
                       AS maxv FROM DUAL));

【讨论】:

对于两个参数,有一个更简单的公式:coalesce(least(x, y), x, y) 这更简单,因为只有 2 个函数调用。对于 3 个或更多参数,我相信您的解决方案是最紧凑的。【参考方案2】:

我怀疑这实际上是您的问题。也许你正在做类似的事情?

select least(some_column) from dual

如果是这样,请将其更改为:

select least(some_column) from dual where some_column is not null

或者,如果你正在做类似这样的事情,你不能只使用where 来过滤集合,

select least(expr1,expr2,expr3) from dual

这样做:

select least(coalesce(expr1, 12345), coalesce(expr2, 12345), coalesce(expr3, 12345)) from dual

其中12345 是一个足够大的值,只有在所有其他表达式都是NULL 时才会选择它。

【讨论】:

感谢@tenfour,我不得不比较多个结果,其中一些结果可能是 NULL。合并解决了我的问题。 LEAST 应始终使用至少 2 个参数调用,否则无用;你最初的例子可能会让新手感到困惑。此外,如果所有参数均为 NULL,则返回 12345(或您使用的任意大数字)而不是 NULL 是一个等待发生的错误,恕我直言。 我同意;实际上我觉得如果你想要这种对集合的控制,你应该真正旋转它,也许使用子查询分解,然后逻辑变得更加理智。【参考方案3】:

第 1 列到第 N 列的最小值:

SELECT
    LEAST(COALESCE(Col1, BINARY_DOUBLE_INFINITY),
          COALESCE(Col2, BINARY_DOUBLE_INFINITY),
          ... ,
          COALESCE(ColN, BINARY_DOUBLE_INFINITY)
    )
FROM MY_TABLE

第 1 列到第 N 列的最大值:

SELECT
    GREATEST(
        COALESCE(Col1, -BINARY_DOUBLE_INFINITY),
        COALESCE(Col2, -BINARY_DOUBLE_INFINITY),
        ..., 
        COALESCE(ColN, -BINARY_DOUBLE_INFINITY)
    )
FROM MY_TABLE

要从查询中删除无穷大的结果,只需添加 where 子句检查所有值是否为空。你也可以使用 coalesce 函数来做到这一点:

WHERE COALESCE(Col1, Col2, ..., ColN) IS NOT NULL

【讨论】:

【参考方案4】:

在三个 'coalesce' 调用中以三个顺序使用三个表达式并将它们放在 'least' 调用中将导致三个中最小的一个,忽略 null 除非所有三个表达式都为 null。

select least(coalesce(expr1, expr2, expr3), coalesce(expr2, expr3, expr1), coalesce(expr3, expr1, expr2)) from dual

【讨论】:

很抱歉,接受的答案对我来说看起来更好【参考方案5】:

一种方法是定义自己的LEAST/GREATEST func 版本:

-- here version for two params
WITH  FUNCTION least_improved(p1 IN NUMBER, p2 IN NUMBER) RETURN NUMBER IS
BEGIN
    IF p1 IS NULL THEN
       RETURN p2;
    ELSIF p2 IS NULL THEN
       RETURN p1;
    ELSE
       RETURN LEAST(p1, p2);
    END IF; 
END;
SELECT least_improved(col1, col2)
FROM table_name;
/

【讨论】:

【参考方案6】:

如果您有很多列需​​要最小值和最大值,您可以将它们取消透视到单个列中,这样就很简单了;从您的单列中排除 NULLS 并使用 MIN() 或 MAX() 来获得您想要的。

我需要使用大约 50 个日期列(不是一个出色的数据库设计)来完成此操作,而 UNPIVOT 似乎是最明智/最实用的方法

【讨论】:

【参考方案7】:
SELECT least(1, 2, 3, nvl(NULL,4)) FROM dual

返回:1

SELECT GREATEST(1, 2, 3, nvl(NULL,0)) FROM dual

返回:3

【讨论】:

以上是关于Oracle SQL 中的最小值但不为 NULL的主要内容,如果未能解决你的问题,请参考以下文章

sql server中的CTE返回空值但不是NULL问题

oracle的sql怎么判断不为null

逗号分隔值循环使用硬编码值但不使用参数值

Oracle中查询某字段不为空的SQL语句怎么写

oracle在sql中判断字段值是数字还是字符串

MS Access SQL:聚合最小值但检索其他字段