将空值计数为唯一值

时间:2013-02-23 12:37:52

标签: sql oracle count 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,他们想要我对所有解决方案的这些要求:

  

尽量减少解决查询所需的子查询数量。   此外,您不能使用以下结构:

     
      
  • FROM或SELECT中的SELECT。您可以拥有子查询(在WHERE或HAVING中选择)
  •   
  • 聚合函数的组合,例如COUNT(COUNT。...),SUM(COUNT ...))等。
  •   
  • UNION如果可以避免它。
  •   
  • 非标准功能(如NVL)
  •   
  • CASE
  •   

11 个答案:

答案 0 :(得分:23)

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

答案 1 :(得分:17)

如果小时是一个数字,那么它是否只能是一个整数:

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

否则,如果它可以是任何浮点,则将NULL更改为char字符串。

例如

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

答案 2 :(得分:7)

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

SqlFiddle

答案 3 :(得分:2)

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 ;

答案 4 :(得分:2)

也许

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

会吗?

答案 5 :(得分:2)

<textarea>

答案 6 :(得分:1)

我认为您的要求非常奇怪,因为您几乎肯定只需使用NVL()COALESCE()CASE即可获得更高效的查询。但是,我设法仅使用子查询获得正确的结果(并且应对NULL值的存在与否)。如果不在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

<强> Results

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

这需要付出很多努力来应对这些要求。一个更简单的选择是使用NVL,然后使用两个简单选择之一......:

  1. 使用TO_CHAR将非NULL值转换为数据类型VARCHAR2和NVL,以将NULL值转换为VARCHAR2 'NULL'
  2. 只需使用NVL一个您知道在结果集中永远不会出现的幻数(即由于表格上的限制)。
  3. <强> Query 1

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

    <强> Results

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

答案 7 :(得分:1)

除了COUNT之外,Andres的答案是完全符合要求并且完全不使用任何功能的答案:

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

我为了另一个目的寻找相同的东西(我可以使用任何东西)但是在我看到这个之前它对我来说似乎不正确或有效,谢谢Andres,这样一个简单的解决方案,但却是一个强大的解决方案。 / p>

答案 8 :(得分:0)

我最接近指定标准的是: (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
)

<强> Results

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

在给定其他限制的情况下,不确定是否允许ROWID伪列,但它可以正常处理NULL值。我不认为ROWID存在于Oracle之外,因此这可能违背了问题的精神,但它至少符合列出的标准。

答案 9 :(得分:-1)

啊!功课啊。这不简单吗?

SELECT COUNT(hour) 
  FROM hours

NULLS不计算在内。

知道了!我不能正确阅读要求。

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

答案 10 :(得分:-1)

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

它将为您提供输出3