Contando valores nulos e não nulos em uma única consulta

141

Eu tenho uma mesa

create table us
(
 a number
);

Agora eu tenho dados como:

a
1
2
3
4
null
null
null
8
9

Agora eu preciso de uma única consulta para contar valores nulos e não nulos na coluna a

Eric
fonte
3
Oi, onde você precisa para este tipo de código de banco de dados de contagem em qual banco de dados a linguagem que estamos falando Atenciosamente, Iordan
IordanTanev
2
Estou surpreso resposta única contém uma união simples de SELECT COUNT (*) ...
Lieven Keersmaekers
1
@ Lieven: Por que diabos você usaria um unionaqui? A resposta de Montecristo é de longe a melhor solução.
Eric
1
Porque o OP quer isso com uma única consulta. A resposta de Montecristo, de fato é de longe a melhor solução ... ele só precisa adicionar a união :)
Lieven Keersmaekers
1
E é isso que recebo por ler o título. Irá editar.
1374 Eric as

Respostas:

231

Isso funciona para Oracle e SQL Server (você pode fazê-lo funcionar em outro RDBMS):

select sum(case when a is null then 1 else 0 end) count_nulls
     , count(a) count_not_nulls 
  from us;

Ou:

select count(*) - count(a), count(a) from us;
Rodrigue
fonte
1
Usando a distinção entre count(*)e count(a)também funciona bem comgroup by
shannon 4/15
1
@ Shannon Eu concordo, COUNT(a)é um comentário útil a ser adicionado, mas isso gera um aviso / erro dependendo da sua pilha e pode justificar um comentário no código. Eu preferiria o SUMmétodo
Richard
4
Prefere count(*)acount(1)
Lei Zhao
61

Se entendi corretamente, você deseja contar todos os NULL e todos os NOT NULL em uma coluna ...

Se isso estiver correto:

SELECT count(*) FROM us WHERE a IS NULL 
UNION ALL
SELECT count(*) FROM us WHERE a IS NOT NULL

Editado para ter a consulta completa, depois de ler os comentários:]


SELECT COUNT(*), 'null_tally' AS narrative 
  FROM us 
 WHERE a IS NULL 
UNION
SELECT COUNT(*), 'not_null_tally' AS narrative 
  FROM us 
 WHERE a IS NOT NULL;
Alberto Zaccagni
fonte
7
+1: de longe a maneira mais simples e rápida. Fiquei chocado quando todas as respostas não foram essas.
Eric
6
Sim mas não. Eu acho que ele quer ter o número de NULL e não NULL em apenas uma consulta ... Você está dizendo como fazer isso em duas consultas ...
Romain Linsolas
@romaintaz: Muito bem. Eu li o título como a pergunta. Em cinco edições, ninguém pensou em consertá-lo. Yeesh.
Eric
@romaintaz: Sim, você está certo, eu tomei isso como uma consulta "executar uma vez para identificar quantos nulos temos", nem sei por que ^^ ', vou corrigir, obrigado.
Alberto Zaccagni
1
@Montecristo: Porque o título pediu única contagem null:)
Eric
42

Aqui está uma versão rápida e suja que funciona no Oracle:

select sum(case a when null then 1 else 0) "Null values",
       sum(case a when null then 0 else 1) "Non-null values"
from us
christopheml
fonte
3
Sintaxe semelhante também funcionaria no SQL Server. Além disso, fazê-lo dessa maneira só examinará a tabela uma vez; as soluções UNION farão duas varreduras de tabela. Irrelevante para mesas pequenas, muito importante para mesas enormes.
13119 Philip Kelley
2
Somente a alteração para o SQL Server "Null values"teria que se tornar 'Null values'. Aspas simples, não duplas.
Eric
1
O SQLServer usa uma varredura de índice para esta consulta vs duas buscas de índice usando uma união. Em uma tabela com 40.000 linhas, não há diferença de velocidade.
Lieven Keersmaekers
1
Em uma tabela com 11.332.581 linhas, há duas varreduras de tabela , sem diferença de velocidade perceptível (atualmente, a união é um pouco mais rápida).
Lieven Keersmaekers
1
Isso não funcionou para mim no Oracle 11g. A versão @ user155789 postada com "case quando a é nulo e depois mais 1 final" foi a sintaxe que funcionou.
21412 Steve Steve
25

Como eu entendi sua consulta, você acabou de executar esse script e obter linhas Total Null, Total NotNull,

select count(*) - count(a) as 'Null', count(a) as 'Not Null' from us;
Ariful Haque
fonte
23

para não nulos

select count(a)
from us

para nulos

select count(*)
from us

minus 

select count(a)
from us

Conseqüentemente

SELECT COUNT(A) NOT_NULLS
FROM US

UNION

SELECT COUNT(*) - COUNT(A) NULLS
FROM US

deveria fazer o trabalho

Melhor que os títulos das colunas saiam corretos.

SELECT COUNT(A) NOT_NULL, COUNT(*) - COUNT(A) NULLS
FROM US

Em alguns testes no meu sistema, custa uma verificação completa da tabela.

EvilTeach
fonte
4
Bom molho, cara, veja os planos de execução para essas consultas. Você está iniciando as digitalizações de mesa para a esquerda e para a direita, especialmente onde há uma declaração tão simples ( select count(*) from t where a is null) que faz isso.
Eric
2
Não tenho um banco de dados à mão para procurar, mas a coluna está indexada ou não. Se for, isso acontece através de uma varredura de intervalo; caso contrário, você ficará praticamente com uma varredura de tabela completa. No oracle, os NULLs não são armazenados no índice, então suspeito que o seu exemplo não seja muito melhor. Sua milhagem pode muito.
EvilTeach
1
@EvilTeach: os índices são úteis apenas quando você não está recuando> ~ 10% das linhas. Depois disso, as verificações completas são iniciadas. Nesse caso, você fará a digitalização pelo menos uma vez, se não duas.
Eric
19

geralmente eu uso esse truque

select sum(case when a is null then 0 else 1 end) as count_notnull,
       sum(case when a is null then 1 else 0 end) as count_null
from tab
group by a
elle0087
fonte
6

Isso é um pouco complicado. Suponha que a tabela tenha apenas uma coluna e, em seguida, o Count (1) e o Count (*) fornecerão valores diferentes.

set nocount on
    declare @table1 table (empid int)
    insert @table1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(NULL),(11),(12),(NULL),(13),(14);

    select * from @table1
    select COUNT(1) as "COUNT(1)" from @table1
    select COUNT(empid) "Count(empid)" from @table1

Resultados da consulta

Como você pode ver na imagem, o primeiro resultado mostra que a tabela possui 16 linhas. das quais duas linhas são NULL. Então, quando usamos Count (*), o mecanismo de consulta conta o número de linhas; portanto, obtemos o resultado como 16. Mas, no caso de Count (empid), ele contava os valores que não são NULL na coluna empid . Então obtivemos o resultado como 14.

portanto, sempre que estivermos usando COUNT (coluna), certifique-se de cuidar dos valores NULL conforme mostrado abaixo.

select COUNT(isnull(empid,1)) from @table1

contará os valores NULL e Non-NULL.

Nota : O mesmo se aplica mesmo quando a tabela é composta por mais de uma coluna. Count (1) fornecerá o número total de linhas, independentemente dos valores NULL / Non-NULL. Somente quando os valores da coluna são contados usando Count (Column), precisamos cuidar dos valores NULL.

Santhoshkumar LM
fonte
4

Eu tive um problema semelhante: contar todos os valores distintos, contando valores nulos como 1 também. Uma contagem simples não funciona nesse caso, pois não leva em consideração valores nulos.

Aqui está um trecho que funciona no SQL e não envolve a seleção de novos valores. Basicamente, uma vez realizado o distinto, também retorne o número da linha em uma nova coluna (n) usando a função row_number () e execute uma contagem nessa coluna:

SELECT COUNT(n)
FROM (
    SELECT *, row_number() OVER (ORDER BY [MyColumn] ASC) n
    FROM (
        SELECT DISTINCT [MyColumn]
                    FROM [MyTable]
        ) items  
) distinctItems
Starnuto di topo
fonte
3

Aqui estão duas soluções:

Select count(columnname) as countofNotNulls, count(isnull(columnname,1))-count(columnname) AS Countofnulls from table name

OU

Select count(columnname) as countofNotNulls, count(*)-count(columnname) AS Countofnulls from table name
Amal Hari
fonte
3

Experimentar

SELECT 
   SUM(ISNULL(a)) AS all_null,
   SUM(!ISNULL(a)) AS all_not_null
FROM us;

Simples!

Rodrigo Prazim
fonte
3

Tente isso ..

SELECT CASE 
         WHEN a IS NULL THEN 'Null' 
         ELSE 'Not Null' 
       END a, 
       Count(1) 
FROM   us 
GROUP  BY CASE 
            WHEN a IS NULL THEN 'Null' 
            ELSE 'Not Null' 
          END 
Ayush Raj
fonte
2

Se você estiver usando o MS Sql Server ...

SELECT COUNT(0) AS 'Null_ColumnA_Records',
(
    SELECT COUNT(0)
    FROM your_table
    WHERE ColumnA IS NOT NULL
) AS 'NOT_Null_ColumnA_Records'
FROM your_table
WHERE ColumnA IS NULL;

Eu não recomendo que você faça isso ... mas aqui está (na mesma tabela como resultado)

Andrei
fonte
2

use a função incorporada ISNULL.


Serget
fonte
Esta também é uma resposta digna. Eu pessoalmente descobriu que COUNT (ISNULL distintas (A, '')) funciona ainda melhor, em seguida, COUNT (DISTINCT A) + SUM (caso quando uma for nulo, 1 ELSE 0 END)
Vladislav
1

se for mysql, você pode tentar algo como isto.

select 
   (select count(*) from TABLENAME WHERE a = 'null') as total_null, 
   (select count(*) from TABLENAME WHERE a != 'null') as total_not_null
FROM TABLENAME
TigerTiger
fonte
1
SELECT SUM(NULLs) AS 'NULLS', SUM(NOTNULLs) AS 'NOTNULLs' FROM 
    (select count(*) AS 'NULLs', 0 as 'NOTNULLs' FROM us WHERE a is null
    UNION select 0 as 'NULLs', count(*) AS 'NOTNULLs' FROM us WHERE a is not null) AS x

É fugaz, mas retornará um único registro com 2 cols, indicando a contagem de nulos vs não nulos.

C-Pound Guru
fonte
1

Isso funciona em T-SQL. Se você está apenas contando o número de algo e deseja incluir os nulos, use COALESCE em vez de maiúsculas e minúsculas.

IF OBJECT_ID('tempdb..#us') IS NOT NULL
    DROP TABLE #us

CREATE TABLE #us
    (
    a INT NULL
    );

INSERT INTO #us VALUES (1),(2),(3),(4),(NULL),(NULL),(NULL),(8),(9)

SELECT * FROM #us

SELECT CASE WHEN a IS NULL THEN 'NULL' ELSE 'NON-NULL' END AS 'NULL?',
        COUNT(CASE WHEN a IS NULL THEN 'NULL' ELSE 'NON-NULL' END) AS 'Count'
    FROM #us
    GROUP BY CASE WHEN a IS NULL THEN 'NULL' ELSE 'NON-NULL' END

SELECT COALESCE(CAST(a AS NVARCHAR),'NULL') AS a,
        COUNT(COALESCE(CAST(a AS NVARCHAR),'NULL')) AS 'Count'
    FROM #us
    GROUP BY COALESCE(CAST(a AS NVARCHAR),'NULL')
DaveX
fonte
1

Partindo de Alberto, adicionei o pacote.

 SELECT [Narrative] = CASE 
 WHEN [Narrative] IS NULL THEN 'count_total' ELSE    [Narrative] END
,[Count]=SUM([Count]) FROM (SELECT COUNT(*) [Count], 'count_nulls' AS [Narrative]  
FROM [CrmDW].[CRM].[User]  
WHERE [EmployeeID] IS NULL 
UNION
SELECT COUNT(*), 'count_not_nulls ' AS narrative 
FROM [CrmDW].[CRM].[User] 
WHERE [EmployeeID] IS NOT NULL) S 
GROUP BY [Narrative] WITH CUBE;
Brian Connelly
fonte
1
SELECT
    ALL_VALUES
    ,COUNT(ALL_VALUES)
FROM(
        SELECT 
        NVL2(A,'NOT NULL','NULL') AS ALL_VALUES 
        ,NVL(A,0)
        FROM US
)
GROUP BY ALL_VALUES
Istiaque Hossain
fonte
1
select count(isnull(NullableColumn,-1))
Imran Shamszadeh
fonte
2
Embora esse código possa responder à pergunta, fornecer um contexto adicional a respeito de por que e / ou como esse código responde à pergunta melhora seu valor a longo prazo.
Vishal Chhodwani
1

Todas as respostas estão erradas ou extremamente desatualizadas.

A maneira simples e correta de fazer essa consulta é usando a COUNT_IFfunção

SELECT
  COUNT_IF(a IS NULL) AS nulls,
  COUNT_IF(a IS NOT NULL) AS not_nulls
FROM
  us
Martín Fixman
fonte
0

Apenas no caso de você desejar em um único registro:

select 
  (select count(*) from tbl where colName is null) Nulls,
  (select count(*) from tbl where colName is not null) NonNulls 

;-)

Sparhawk_
fonte
0

para contar valores não nulos

select count(*) from us where a is not null;

para contar valores nulos

 select count(*) from us where a is null;
Deep Shah
fonte
1
O op pediu consulta única :)
infografnet
0

Criei a tabela no postgres 10 e funcionou o seguinte:

select count(*) from us

e

select count(a is null) from us

skrillybrick
fonte
a IS NULLproduz TRUEor FALSE, e COUNT () contará todos os valores NOT NULL. Então count(a is null), retornará a contagem de todas as linhas.
ypresto 25/06
0

No meu caso, eu queria a " distribuição nula " entre várias colunas:

SELECT
       (CASE WHEN a IS NULL THEN 'NULL' ELSE 'NOT-NULL' END) AS a_null,
       (CASE WHEN b IS NULL THEN 'NULL' ELSE 'NOT-NULL' END) AS b_null,
       (CASE WHEN c IS NULL THEN 'NULL' ELSE 'NOT-NULL' END) AS c_null,
       ...
       count(*)
FROM us
GROUP BY 1, 2, 3,...
ORDER BY 1, 2, 3,...

De acordo com o '...', é facilmente extensível a mais colunas, quantas forem necessárias

Vzzarr
fonte
-1

Número de elementos em que a é nulo:

select count(a) from us where a is null;

Número de elementos em que a não é nulo:

select count(a) from us where a is not null;
Romain Linsolas
fonte
1
A pergunta é para uma única consulta.
DreamWave