Подсчет значений null как уникального значения

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

Hours
1
1
2
null
null
null

результат должен быть: 3. Мой вопрос:

select count(distinct hour) from hours;

но он возвращает: 2. Я проверил также:

select count(*) from hours group by hour

но он возвращает три строки:

(1) 3
(2) 2
(3) 1

как я могу считать нулевые значения как 1 значение и использовать distinct, чтобы избежать повторного подсчета значений?

Я изучаю расширенный SQL, они хотят, чтобы я эти требования для всех решений:

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

  • выберите из или выберите. Вам разрешено иметь подзапросы (выберите в WHERE или HAVING)
  • комбинации агрегационных функций, таких как COUNT (COUNT. ..)), SUM (COUNT. ..)) и тому подобное.
  • союз, если вы можете избежать этого.
  • нестандартные функции (такие как NVL)
  • случае

12 ответов


select  count(distinct col1) + count(distinct case when col1 is null then 1 end)
from    YourTable

Если час-это число, то если это может быть только целое число:

select count(distinct coalesce(hour, 0.1)) cnt from test;

в противном случае, если это может быть любая плавающая точка, измените NULL на строку char.

например

select count(distinct coalesce(to_char(hour), 'a')) cnt from test;

select 
   count(0) 
from
  (
      select distinct hour from hours
  )

SqlFiddle


SELECT
      ( SELECT COUNT(DISTINCT hour)
        FROM hours
      )
    + CASE WHEN EXISTS
           ( SELECT *
             FROM hours
             WHERE hour IS NULL
           )
        THEN 1 
        ELSE 0
      END
   AS result
FROM dual ;

я бы сказал, что ваши требования довольно странные, учитывая, что вы почти наверняка получите более эффективный запрос, просто используя NVL(), COALESCE() или CASE. Тем не менее, мне удалось получить правильный результат (и справиться с наличием или отсутствием NULL values), используя только подзапросы. Мне не удалось сделать это без использования подзапроса в FROM пункт еще.

SQL Fiddle

запрос 1:

SELECT nnh.not_null_hours + nh.null_hours
FROM (
  SELECT COUNT(DISTINCT t.hour) not_null_hours
  FROM example_table t
) nnh
CROSS JOIN (
  SELECT 1 null_hours
  FROM dual
  WHERE EXISTS (
    SELECT 1
    FROM example_table t
    WHERE t.hour IS NULL
  )
  UNION ALL
  SELECT 0 null_hours
  FROM dual
  WHERE NOT EXISTS (
    SELECT 1
    FROM example_table t
    WHERE t.hour IS NULL
  )
) nh

результаты:

| NNH.NOT_NULL_HOURS+NH.NULL_HOURS |
------------------------------------
|                                3 |

это много усилий, чтобы справиться с требованиями. Гораздо более простой вариант-использовать NVL, а затем один из двух простых вариантов... либо:

  1. использовать TO_CHAR для преобразования ненулевых значений в тип данных VARCHAR2 и NVL преобразование NULL значения для VARCHAR2 'NULL' или
  2. просто использовать NVL с магическим числом, что вы знаете, что никогда не будете присутствовать в результирующем наборе (т. е. из-за ограничений на таблице).

запрос 1:

SELECT 
  COUNT(DISTINCT NVL(TO_CHAR(hour), 'NULL')) using_to_char_null
, COUNT(DISTINCT NVL(hour, -1)) using_magic_number
FROM example_table

результаты:

| USING_TO_CHAR_NULL | USING_MAGIC_NUMBER |
-------------------------------------------
|                  3 |                  3 |

может быть

    select count(distinct hour||' ') from hours;

будет делать?


ответ Андрес-это тот, который отвечает требованиям отлично и без использования какой-либо функции вообще, кроме COUNT:

select count(distinct hour||' ') from hours;

select count(distinct nvl(hour,0)) from hours;

ближе всего я мог бы получить соответствие указанным критериям, это: (SQL Fiddle)

запрос 1:

SELECT COUNT(*)
FROM example_table t1
WHERE t1.ROWID IN (
  SELECT MAX(t2.ROWID)
  FROM example_table t2
  GROUP BY t2.hour
)

результаты:

| COUNT(*) |
------------
|        3 |

не уверен, что если ROWID псевдостолбцом допускается, с учетом других ограничений, но он работает и корректно обрабатывает NULL значения. Я не думаю, что ROWID существует вне Oracle, поэтому, вероятно, это противоречит духу вопроса, но это соответствует критерии в списке по крайней мере.


вероятно, самый простой способ-использовать DUMP:

SELECT COUNT(DISTINCT DUMP(hour)) AS distinct_count
FROM hours;

выход: 3

Демо DBFiddle


Ах.. домашнее задание. Разве все не так просто?

SELECT COUNT(hour) 
  FROM hours

нули не учитываются.

понял! Мой плохой для не чтения требований должным образом.

SELECT COUNT(DISTINCT COALESCE(hour,-1)) 
  FROM hours

Select count(1)-count(hour) from hours;

это даст вам выход 3