Подсчет ненулевых столбцов довольно странным образом - PullRequest
1 голос
/ 19 июня 2009

У меня есть таблица с 32 столбцами в таблице Oracle.

  • Два из этих столбцов являются столбцами идентификаторов
  • остальные значения

Я хотел бы получить среднее значение для всех столбцов значений, что усложняется нулевыми (идентичными) столбцами. Ниже приведен псевдокод того, чего я пытаюсь достичь:

    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. Нечто, возвращающее 0, если значение равно нулю, и 1, если нет, а не само значение.

Как мне узнать значение знаменателя?


PS: я чувствую, что должен объяснить некоторые мотивы этого дизайна. В идеале эта таблица была бы организована как столбцы идентификаторов и одно значение в строке с некоторым идентификатором для самой строки. Это сделало бы его более нормализованным, и решение этой проблемы было бы довольно простым. Причинами, по которым этого не следует делать, являются пропускная способность и экономия места. Это огромная БД, куда мы вставляем 10 миллионов значений в минуту. Создание каждого из этих значений одной строкой будет означать 10 миллионов строк в минуту, что определенно недостижимо. Упаковка 30 из них в одну строку уменьшает количество вставляемых строк до того, что мы можем сделать с одной БД, а объем служебных данных (идентификационных данных) намного меньше.

Ответы [ 5 ]

2 голосов
/ 19 июня 2009

(случай, когда col равно нулю, затем 0 или 1 конец)

1 голос
/ 20 января 2014

Я вижу, что это довольно старый вопрос, но я не вижу достаточного ответа. У меня была похожая проблема, и ниже, как я решил ее. Совершенно очевидно, что заявление о ситуации необходимо. Это решение является обходным решением для таких случаев, когда

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;


Ура!
Doug

1 голос
/ 19 июня 2009

Другой вариант - использовать функцию 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, чтобы сделать его еще проще.

1 голос
/ 19 июня 2009

Вы можете использовать NVL2(val0, 1, 0) + NVL2(val1, 1, 0) + ..., поскольку вы используете Oracle.

0 голосов
/ 19 июня 2009

Как правило, вы можете сделать что-то вроде этого:

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

Верхняя строка возвращает сумму значений (без значений NULL), а нижняя строка возвращает количество ненулевых значений.

FYI - это синтаксис SQL Server, но COALESCE по большей части похож на ISNULL SIGN просто возвращает -1 для отрицательного числа, 0 для нуля и 1 для положительного числа. ABS - это «абсолютное значение».

...