Как рассчитать, сколько нулевых значений присутствует в каждом столбце? - PullRequest
0 голосов
/ 30 апреля 2019

У меня есть таблица А вот так:

col1col2col3
1 0null
nullnullnull
3nullnull
null 5 1

Я хочу вывод, подобный этому, в Oracle 10G :

column_namenull_count
col1 2
col2 2
col3 3

Я достиг этого, используя UNION ALL , например:

select "col1" column_name,sum(case when col1 is null then 1 else 0 end) as null_count from A group by "col1"
union all
select "col2" column_name,sum(case when col2 is null then 1 else 0 end) as null_count from A group by "col2"
union all
select "col3" column_name,sum(case when col3 is null then 1 else 0 end) as null_count from A group by "col3";

Работает нормально, но отнимает много времени, так как есть почти 100 UNION ALL s. Я хочу добиться того же результата без использования UNION ALL .

Есть ли способ достичь этого без использования UNION ALL ?

Ответы [ 3 ]

1 голос
/ 30 апреля 2019

Вы можете использовать UNPIVOT для этого (я не уверен, что древний Oracle 10 уже поддерживал это - я не использовал это более десяти лет)

select colname, count(*) - count(val) as num_nulls
from t1
  UNPIVOT include nulls 
      (val for colname in (col1 as 'C1', 
                           col2 as 'C2', 
                           col3 as 'C3'))
group by colname
order by colname; 

Не уверен, что так быстрее.

Онлайн пример: https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=4e807b8b2d8080abac36574f776dbf04

0 голосов
/ 30 апреля 2019

Oracle 10g не поддерживает операторы UNPIVOT и PIVOT, поэтому, чтобы сделать то, что вам нужно в 10g, вам нужно использовать фиктивную таблицу (содержащую то же количество строк, что и столбцы, которые не были развернуты - в вашем случае вот это 3), вот так:

WITH your_table AS (SELECT 1 col1, 0 col2, NULL col3 FROM dual UNION ALL
                    SELECT NULL col1, NULL col2, NULL col3 FROM dual UNION ALL
                    SELECT 3 col1, NULL col2, NULL col3 FROM dual UNION ALL
                    SELECT NULL col1, 5 col2, 1 col3 FROM dual)
SELECT CASE WHEN dummy.id = 1 THEN 'col1'
            WHEN dummy.id = 2 THEN 'col2'
            WHEN dummy.id = 3 THEN 'col3'
       END column_name,
       COUNT(CASE WHEN dummy.id = 1 THEN CASE WHEN col1 IS NULL THEN 1 END
                  WHEN dummy.id = 2 THEN CASE WHEN col2 IS NULL THEN 1 END
                  WHEN dummy.id = 3 THEN CASE WHEN col3 IS NULL THEN 1 END
             END) null_count
FROM   your_table
       CROSS JOIN (SELECT LEVEL ID
                   FROM   dual
                   CONNECT BY LEVEL <= 3) dummy
GROUP BY dummy.id;

COLUMN_NAME NULL_COUNT
----------- ----------
col1                 2
col2                 2
col3                 3

Если вы считаете, что для написания большого количества столбцов потребуется время, вы всегда можете написать запрос, который сам сгенерирует основную часть операторов case, например ::

SELECT 'when dummy.id = '||row_number() OVER (PARTITION BY owner, table_name ORDER BY column_id)||' then '''||LOWER(column_name)||'''' first_part,
       'when dummy.id = '||row_number() OVER (PARTITION BY owner, table_name ORDER BY column_id)||' then case when '||column_name||' is null then 1 end' second_part
FROM   all_tab_columns a
WHERE  owner = ...
AND    table_name = ...
-- and column_name in (...)
ORDER BY column_id;

(я включил аналитическую функцию row_number() вместо использования column_id, потому что если вы исключаете некоторые столбцы, столбец column_id больше не будет последовательными числами, начинающимися с 1.)

0 голосов
/ 30 апреля 2019

Я бы порекомендовал этот запрос:

SELECT 'col1' AS col_name, COUNT(*) - COUNT(col1) AS col_null_count FROM t UNION ALL
SELECT 'col2' AS col_name, COUNT(*) - COUNT(col2) AS col_null_count FROM t UNION ALL
SELECT 'col3' AS col_name, COUNT(*) - COUNT(col3) AS col_null_count FROM t

Но вы можете попробовать написать это так:

WITH cte AS (
    -- 1 rows by n columns
    SELECT COUNT(*) - COUNT(col1) AS col1_null_count
         , COUNT(*) - COUNT(col2) AS col2_null_count
         , COUNT(*) - COUNT(col3) AS col3_null_count
    FROM t
)
-- n rows by 2 columns
SELECT 'col1' AS col_name, col1_null_count AS col_null_count FROM cte UNION ALL
SELECT 'col2' AS col_name, col2_null_count AS col_null_count FROM cte UNION ALL
SELECT 'col3' AS col_name, col3_null_count AS col_null_count FROM cte
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...