2013-02-23 16 views
12

devo contare valori diversi su una colonna, come ad esempio:conteggio valori nulli come unico valore

Hours 
1 
1 
2 
null 
null 
null 

Il risultato deve essere: . La mia domanda è:

select count(distinct hour) from hours; 

ma restituisce: 2. Ho testato anche:

select count(*) from hours group by hour 

ma restituisce tre file:

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

Come posso contare valori nulli come 1 Valore e usare distinti per evitare di contare i valori ripetuti?

sto imparando SQL avanzato, Vogliono che questi requisiti per tutte le soluzioni:.

"Cerca di minimizzare il numero di sottoquery è necessario risolvere la query Inoltre, non si è autorizzati ad utilizzare il seguente costruzioni: "

  • SELECT in FROM o SELECT. È consentito avere sottoquery (SELECT in WHERE o HAVING)
  • Combinazioni di funzioni di aggregazione come COUNT (COUNT ...)), SUM (COUNT ...) e simili.
  • UNION se puoi evitarlo.
  • funzioni non standard (come ad esempio NVL)
  • CASE
+0

gioco intorno con fondono (Col, 0) – Strawberry

+0

@Strawberry: Che conterebbe '0' e' null' come lo stesso valore – Andomar

+0

sì, sarebbe !!! – Strawberry

risposta

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

Funziona bene, ma sto cercando di fare a meno di 'caso' e con la massima efficienza. – David

+5

@ user2076284 La massima efficienza non corrisponde a tutte le limitazioni arbitrarie che avete posto. –

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

SqlFiddle

+0

+1 per una bella soluzione - preferirei comunque un conteggio (*). –

+0

@DavidAldridge count (0) è molto efficiente del conteggio (*) – Rama

+1

@DRAM Su quale database? Non su Oracle: ti sei innamorato di un mito ampiamente smentito altrove. –

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

È questo CASO QUANDO ESISTE legale in Oracle? –

+0

@DavidAldridge Sì: [SQL-Fiddle] (http://sqlfiddle.com/#!4/fdbee/ 1) –

1

direi che le vostre esigenze sono piuttosto bizzarro, dato che si' quasi certo di ottenere una query più efficiente semplicemente usando NVL(), COALESCE() o CASE. Tuttavia, sono riuscito a ottenere il risultato corretto (e ad affrontare la presenza o l'assenza di valori NULL) utilizzando solo sottoquery. Non sono ancora riuscito a farlo senza utilizzare una sottoquery nella clausola FROM.

SQL Fiddle

Query 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 | 

Questo sta per un grande sforzo per far fronte alle esigenze. Un'opzione molto più semplice è utilizzare NVL e quindi una delle due semplici scelte ...o:

  1. Usa TO_CHAR per convertire i valori non NULL per il tipo di dati VARCHAR2 e NVL convertire NULL valori al VARCHAR2 'NULL' o
  2. Basta usare NVL con un numero magico che si sa non sarà mai presente in il set di risultati (cioè a causa di vincoli sul tavolo).

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

Grazie, penso che sia impossibile fare senza rompere nessuno di questi requisiti, deve essere sbagliato – David

+0

Potrei fare qualcosa con outer join? – David

+0

Non riesco a pensare a condizioni di join utili che è possibile utilizzare senza violare la regola "nessuna subquery nella clausola FROM", ma ho aggiunto un'altra risposta con il massimo impegno per Oracle. Non sono sicuro di poterlo fare ulteriormente con il solo ANSI SQL. – Ben

-1

Ah .. compiti a casa. Non è così semplice?

SELECT COUNT(hour) 
    FROM hours 

NULLS non vengono conteggiati.

Trovato! Il mio male per non aver letto correttamente i requisiti.

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

Ma lui vuole contarli (come uno) se esistono. –

0

Il più vicino ho potuto ottenere il montaggio dei criteri specificati è questo: (SQL Fiddle)

Query 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 | 

Non sono sicuro se la pseudocolonna ROWID è consentita, date le altre restrizioni, ma funziona e gestisce con garbo i valori NULL. Non penso che ROWID esista al di fuori di Oracle, quindi probabilmente questo va contro lo spirito della domanda, ma si adatta ai criteri elencato almeno.

13

se ora è un numero, allora se può essere solo un numero intero:

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

altrimenti se può essere qualsiasi virgola mobile, cambiamento NULL per una stringa char.

esempio

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

forse

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

farà?

+1

Benvenuti in Stack Overflow! Potresti modificare la tua risposta per aggiungere una spiegazione? Ad esempio, quale potrebbe essere la risposta corretta? –

0

risposta da Andres è quello che soddisfa i requisiti perfettamente e senza utilizzare alcun funzione, a parte COUNT:

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

che cercavo stessa cosa per un altro scopo (ho potuto usare qualcosa a tutti) ma non mi è sembrato corretto o efficiente fino a quando non ho visto questo, grazie Andres, una soluzione così semplice ma potente.

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

Probabilmente il modo più semplice è quello di utilizzare DUMP:

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

uscita: 3

DBFiddle Demo