2013-02-23 55 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