以相当奇怪的方式计算非空列

时间:2009-06-19 01:05:50

标签: sql oracle count null

我有一个表,在Oracle表中有32列。

  • 其中两列是标识列
  • 其余的是值

我想得到所有值列的平均值,这些列由null(标识)列复杂化。下面是我想要实现的伪代码:

    SELECT 
           ((nvl(val0, 0) + nvl(val1, 0) + ... nvl(valn, 0)) 
           / nonZero_Column_Count_In_This_Row)

这样:nonZero_Column_Count_In_This_Row =(ifNullThenZeroElse1(val0)+ ifNullThenZeroElse1(val1)... ifNullThenZeroElse(valn))

这里的困难当然是为任何非空列获得1。我似乎需要一个类似于NVL的函数,但是有一个else子句。如果值为null,则返回0,但如果不为则返回1,而不是值本身。

我应该如何获得分母的价值?


PS:我觉得我必须解释这个设计背后的一些动机。理想情况下,此表将组织为标识列,每行一个值,行本身具有一些标识符。这会使它更加规范化,并且解决这个问题的方法非常简单。不这样做的原因是吞吐量和节省空间。这是一个巨大的数据库,我们每分钟插入1000万个值。将这些值中的每一个设为一行意味着每分钟10M行,这绝对是不可能实现的。将它们中的30个打包成一行减少了插入到我们可以使用单个DB执行的操作的行数,并且开销数据量(标识数据)更少。

5 个答案:

答案 0 :(得分:2)

(Case当col为null然后0 else 1结束)

答案 1 :(得分:1)

您可以使用NVL2(val0, 1, 0) + NVL2(val1, 1, 0) + ...,因为您使用的是Oracle。

答案 2 :(得分:1)

另一种选择是使用AVG函数,它忽略NULL:

SELECT AVG(v) FROM (
WITH q AS (SELECT val0, val1, val2, val3 FROM mytable)
SELECT val0 AS v FROM q
UNION ALL SELECT val1 FROM q
UNION ALL SELECT val2 FROM q
UNION ALL SELECT val3 FROM q
);

如果您使用的是Oracle11g,则可以使用UNPIVOT语法使其更简单。

答案 3 :(得分:1)

我认为这是一个非常古老的问题,但我没有看到足够的答案。我有类似的问题,下面就是我解决它的方法。很明显需要一个案例陈述。此解决方案是针对此类情况的解决方法

SELECT COUNT(column) WHERE column {IS | IS NOT} NULL

无论出于何种原因都不起作用,或者,您需要做几个

SELECT   COUNT ( * )
  FROM   A_TABLE
 WHERE   COL1 IS NOT NULL;

SELECT   COUNT ( * )
  FROM   A_TABLE
 WHERE   COL2 IS NOT NULL;

查询但在运行脚本时希望将其作为数据集。见下文;我用这个进行分析,到目前为止它对我来说很有用。

SUM(CASE NVL(valn, 'X')
                WHEN 'X'
                THEN 0 
                ELSE 1 
                END) as COLUMN_NAME
            FROM YOUR_TABLE;


干杯!
道格

答案 4 :(得分:0)

通常,你可以这样做:

SELECT (
       (COALESCE(val0, 0) + COALESCE(val1, 0) + ...... COALESCE(valn, 0))
       /
       (SIGN(ABS(COALESCE(val0, 0))) + SIGN(ABS(COALESCE(val1, 0))) + .... )
       ) AS MyAverage

顶行将返回值的总和(省略NULL值),而底行将返回非空值的数量。

仅供参考 - 它是SQL Server语法,但COALESCE在很大程度上就像ISNULL。 SIGN只返回-1表示负数,0表示零,1表示正数。 ABS是“绝对价值”。