Contando valores nulos y no nulos en una sola consulta

141

Tengo una mesa

create table us
(
 a number
);

Ahora tengo datos como:

a
1
2
3
4
null
null
null
8
9

Ahora necesito una sola consulta para contar valores nulos y no nulos en la columna a

Eric
fuente
3
Hola, ¿dónde se necesita para este tipo de código de la base de datos de conteo en lo base de datos lingüística estamos hablando Best Regards, Iordan
IordanTanev
2
Estoy sorprendido hay una respuesta única contiene una unión sencilla de seleccionar la cuenta (*) ...
Lieven Keersmaekers
1
@Lieven: ¿Por qué demonios usarías un unionaquí? La respuesta de Montecristo es, con mucho, la mejor solución.
Eric
1
Porque OP lo quiere con una sola consulta. La respuesta de Montecristo de hecho es, con mucho, la mejor solución ... sólo tiene que añadir la unión :)
Lieven Keersmaekers
1
Y eso es lo que obtengo por leer el título. Se editará
Eric

Respuestas:

231

Esto funciona para Oracle y SQL Server (es posible que pueda hacer que funcione en otro RDBMS):

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

O:

select count(*) - count(a), count(a) from us;
Rodrigue
fuente
1
Usar la distinción entre count(*)y count(a)también funciona bien congroup by
shannon
1
@shannon Estoy de acuerdo, COUNT(a)es un comentario útil para agregar, pero esto arroja una advertencia / error dependiendo de su pila y podría justificar un comentario en el código. Preferiría el SUMmétodo
Richard
44
Prefiero count(*)acount(1)
Lei Zhao
61

Si entendí correctamente, desea contar todo NULL y todo NOT NULL en una columna ...

Si eso es correcto:

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

Editado para tener la consulta completa, después de leer los comentarios:]


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
fuente
77
+1: Con mucho, la forma más simple y rápida. Me sorprendió cuando cada respuesta no era esta.
Eric
66
Si pero no. Creo que él quiere tener el número de NULL y no es NULL en una sola consulta ... Usted está diciendo cómo hacer eso en dos consultas ...
Romain Linsolas
@romaintaz: Muy bien. Leí el título como la pregunta. En cinco ediciones, nadie pensó en arreglarlo. Yeesh
Eric
@romaintaz: Sí, tienes razón, lo he tomado como una "consulta de ejecución única para detectar cuántos valores nulos tenemos", ni siquiera sé por qué ^^ ', voy a corregir, gracias.
Alberto Zaccagni
1
@Montecristo: Porque el título solo pedía contar null:)
Eric
42

Aquí hay una versión rápida y sucia que funciona en 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
fuente
3
Una sintaxis similar también funcionaría en SQL Server. Además, hacerlo de esta manera solo escaneará la tabla una vez; Las soluciones UNION harán dos escaneos de tabla. Irrelevante para mesas pequeñas, muy importante para las grandes.
Philip Kelley
2
El único cambio para SQL Server "Null values"debería hacerse 'Null values'. Comillas simples, no dobles.
Eric
1
SQLServer utiliza una exploración de índice para esta consulta frente a dos búsquedas de índice utilizando una unión. En una mesa con 40,000 filas, no hay diferencia de velocidad.
Lieven Keersmaekers
1
En una tabla con 11.332.581 filas, hay dos escaneos de tabla , sin diferencia de velocidad notable (en realidad, la unión es un poco más rápida).
Lieven Keersmaekers
1
Esto no funcionó para mí en Oracle 11g. La versión @ user155789 publicada con "caso cuando a es nulo y luego 1 más 0 final" fue la sintaxis que funcionó.
Steve
25

Como entendí tu consulta, solo ejecutas este script y obtienes filas Total Null, Total NotNull,

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

para no nulos

select count(a)
from us

para nulos

select count(*)
from us

minus 

select count(a)
from us

Por lo tanto

SELECT COUNT(A) NOT_NULLS
FROM US

UNION

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

debería hacer el trabajo

Mejor en eso los títulos de columna salen correctos.

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

En algunas pruebas en mi sistema, cuesta un escaneo completo de la tabla.

EvilTeach
fuente
44
Buena salsa, hombre, mira los planes de ejecución para estas consultas. Estás iniciando los escaneos de mesa de izquierda a derecha, especialmente donde hay una declaración tan simple select count(*) from t where a is nullque hace esto.
Eric
2
No tengo una base de datos a mano para buscar, pero la columna está indexada o no. Si es así, sucede a través de un escaneo de rango, de lo contrario, le queda prácticamente un escaneo de tabla completo. En Oracle, los NULL no se almacenan en el índice, por lo que sospecho que su ejemplo no es mucho mejor. Tu kilometraje puede muy.
EvilTeach
1
@EvilTeach: los índices solo son útiles cuando no retrocede> ~ 10% de las filas. Después de eso, se inician exploraciones completas. En este caso, obtendrá el escaneo al menos una vez, si no dos veces.
Eric
19

usualmente uso este truco

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
fuente
6

Esto es un poco complicado. Suponga que la tabla tiene solo una columna, entonces el Conteo (1) y el Conteo (*) darán 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 de consultas

Como puede ver en la imagen, el primer resultado muestra que la tabla tiene 16 filas. de las cuales dos filas son NULL. Entonces, cuando usamos Count (*), el motor de consulta cuenta el número de filas, así que obtuvimos el resultado de la cuenta como 16. Pero en el caso de Count (empid) contó los valores no NULL en la columna vacía . Entonces obtuvimos el resultado como 14.

así que cada vez que usemos COUNT (Columna) asegúrese de cuidar los valores NULL como se muestra a continuación.

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

contará los valores NULL y Non-NULL.

Nota : Lo mismo se aplica incluso cuando la tabla está compuesta por más de una columna. Count (1) dará el número total de filas independientemente de los valores NULL / Non-NULL. Solo cuando los valores de la columna se cuentan utilizando Count (Column) necesitamos cuidar los valores NULL.

Santhoshkumar LM
fuente
4

Tuve un problema similar: contar todos los valores distintos, contando los valores nulos como 1 también. Un recuento simple no funciona en este caso, ya que no tiene en cuenta los valores nulos.

Aquí hay un fragmento que funciona en SQL y no implica la selección de nuevos valores. Básicamente, una vez realizado el distintivo, también devuelve el número de fila en una nueva columna (n) utilizando la función row_number (), luego realiza un recuento en esa columna:

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

Aquí hay dos soluciones:

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

O

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

Tratar

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

¡Sencillo!

Rodrigo Prazim
fuente
3

Prueba esto..

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
fuente
2

Si está utilizando 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;

No te recomiendo que hagas esto ... pero aquí lo tienes (en la misma tabla como resultado)

Andrei
fuente
2

use la función incrustada ISNULL.


Serget
fuente
Esta también es una respuesta digna. Personalmente descubrí que COUNT (DISTINCT ISNULL (A, '')) funciona aún mejor que COUNT (DISTINCT A) + SUM (CASO CUANDO A ES NULO ENTONCES 1 OTRO 0 FIN)
Vladislav
1

si es mysql, puedes probar algo como esto.

select 
   (select count(*) from TABLENAME WHERE a = 'null') as total_null, 
   (select count(*) from TABLENAME WHERE a != 'null') as total_not_null
FROM TABLENAME
Tigre
fuente
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

Es fugoso, pero devolverá un único registro con 2 cols que indica el recuento de nulos frente a no nulos.

C-Pound Guru
fuente
1

Esto funciona en T-SQL. Si solo cuenta el número de algo y desea incluir los valores nulos, use COALESCE en lugar de mayú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
fuente
1

Partiendo de Alberto, agregué el paquete acumulativo.

 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
fuente
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
fuente
1
select count(isnull(NullableColumn,-1))
Imran Shamszadeh
fuente
2
Si bien este código puede responder a la pregunta, proporcionar un contexto adicional con respecto a por qué y / o cómo este código responde a la pregunta mejora su valor a largo plazo.
Vishal Chhodwani
1

Todas las respuestas son incorrectas o extremadamente desactualizadas.

La forma simple y correcta de hacer esta consulta es mediante la COUNT_IFfunción.

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

Por si acaso lo quisieras en un solo registro:

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

;-)

Gavilán_
fuente
0

para contar valores no nulos

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

para contar valores nulos

 select count(*) from us where a is null;
Shah profundo
fuente
1
El operador solicitó una sola consulta :)
infografnet
0

Creé la tabla en postgres 10 y las dos siguientes funcionaron:

select count(*) from us

y

select count(a is null) from us

Skrillybrick
fuente
a IS NULLproduce TRUEor FALSE, y COUNT () contará todos los valores NOT NULL. Entonces count(a is null)devolverá el recuento de todas las filas.
ypresto
0

En mi caso, quería la " distribución nula " entre varias columnas:

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,...

Según el '...' es fácilmente extensible a más columnas, tantas como sea necesario

Vzzarr
fuente
-1

Número de elementos donde a es nulo:

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

Número de elementos donde a no es nulo:

select count(a) from us where a is not null;
Romain Linsolas
fuente
1
La pregunta es para una sola consulta.
DreamWave