2013-02-23 158 views
12

我需要依靠一列不同的值,如:计数空值作为唯一的值

Hours 
1 
1 
2 
null 
null 
null 

结果必须是:。我的查询是:

select count(distinct hour) from hours; 

但它返回:2.我还测试:

select count(*) from hours group by hour 

但它返回三行:

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

我怎么能算空值的值为1并使用不同的方法来避免重复计数?

我学习先进的SQL,他们希望我为所有的解决方案,这些要求:

“尽量减少你需要解决的查询子查询的数量。此外,您不允许使用以下构造:“

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

玩弄COALESCE(COL,0) – Strawberry 2013-02-23 12:40:05

+0

@Strawberry:那会计数'0'和'空'作为相同的值 – Andomar 2013-02-23 12:40:30

+0

是的,它会!!! – Strawberry 2013-02-23 12:42:47

回答

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

工作正常,但我试图做到没有'case',并且效率最高。 – David 2013-02-23 12:50:18

+5

@ user2076284最大效率与您提出的所有任意限制都不匹配。 – 2013-02-23 13:15:46

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

SqlFiddle

+0

+1为一个很好的解决方案 - 我宁愿自己计数(*)。 – 2013-09-09 18:32:40

+0

@DavidAldridge count(0)非常有效比count(*) – Rama 2015-10-30 02:24:27

+1

@DRAM在什么数据库上?不在甲骨文上 - 你在其他地方被广泛否认的神话所淹没。 – 2015-10-31 09:48:10

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 ; 
+0

这是CASE WHEN EXISTS合法的Oracle吗? – 2013-09-09 18:33:26

+0

@DavidAldridge是:[SQL-Fiddle](http://sqlfiddle.com/#!4/fdbee/ 1) – 2013-09-09 21:53:09

1

我说你的要求是相当奇怪的,因为你”几乎肯定可以简单地使用NVL(),COALESCE()或来获得更高效的查询。但是,我设法得到正确的结果(并应付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和NVLNULL值转换为VARCHAR2 'NULL'
  2. 只需使用NVL有一个神奇的数字,你知道永远不会出现在结果集(即因为表中的约束)。

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 | 
+0

谢谢。我认为这是不可能的,如果没有这个要求,肯定是错的。 – David 2013-02-23 15:15:37

+0

我可以做一些外连接吗? – David 2013-02-23 17:41:07

+0

我想不出任何有用的连接条件,您可以在不违反“FROM子句中的无子查询”规则的情况下使用任何有用的连接条件,但我已尽最大努力为Oracle添加了另一个答案。不知道我是否可以单独使用纯SQL ANSI进一步处理。 – Ben 2013-02-24 18:17:28

-1

啊..功课。这不是很简单吗?

SELECT COUNT(hour) 
    FROM hours 

NULLS不计算在内。

Got it!我的不良因为没有正确阅读要求。

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

但是,如果它们存在,他想要数它们(作为一个)。 – 2013-02-23 16:49:50

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之外,所以这可能违背问题的精神,但它至少符合列出的的标准。

13

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

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

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

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

也许

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

会做什么?

+1

欢迎来到Stack Overflow!你能否编辑你的答案来添加一个解释?例如,什么会导致你的答案是正确的? – 2013-09-09 15:19:15

0

由安德烈的回答是,符合要求完美,不使用任何功能都远离COUNT之一:

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

我一直在寻找同样的东西用于其他目的(我可以用任何东西)但是直到我看到这一个时,我才觉得它不正确或有效率,谢谢Andres,这样一个简单的解决方案,而且功能强大。

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

也许最简单的方法是使用DUMP

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

输出:3

DBFiddle Demo