Comptage des valeurs nulles et non nulles dans une seule requête

141

J'ai une table

create table us
(
 a number
);

Maintenant, j'ai des données comme:

a
1
2
3
4
null
null
null
8
9

Maintenant, j'ai besoin d'une seule requête pour compter les valeurs nulles et non nulles dans la colonne a

Eric
la source
3
Salut, où avez-vous besoin de ce type de code de base de données de comptage dans quelle langue de base de données parlons-nous Meilleures salutations, Iordan
IordanTanev
2
Je suis surpris qu'aucune réponse unique ne contienne une simple union de select count (*) ...
Lieven Keersmaekers
1
@Lieven: Pourquoi diable utiliseriez-vous un unionici? La réponse de Montecristo est de loin la meilleure solution.
Eric
1
Parce que OP le veut avec une seule requête. La réponse de Montecristo est en effet de loin la meilleure solution ... il a juste besoin d'ajouter le syndicat :)
Lieven Keersmaekers
1
Et c'est ce que j'obtiens en lisant le titre. Va éditer.
Eric

Réponses:

231

Cela fonctionne pour Oracle et SQL Server (vous pourrez peut-être le faire fonctionner sur un autre SGBDR):

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
la source
1
Utiliser la distinction entre count(*)et count(a)fonctionne bien avecgroup by
shannon
1
@shannon Je suis d'accord, COUNT(a)est un commentaire utile à ajouter, mais cela génère un avertissement / une erreur en fonction de votre pile et peut justifier un commentaire dans le code. Je préférerais la SUMméthode.
Richard
4
Préférez count(*)àcount(1)
Lei Zhao
61

Si j'ai bien compris, vous voulez compter tous les NULL et tous les NOT NULL dans une colonne ...

Si c'est correct:

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

Modifié pour avoir la requête complète, après avoir lu les commentaires:]


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
la source
7
+1: De loin le moyen le plus simple et le plus rapide. J'ai été choqué lorsque chaque réponse n'était pas celle-ci.
Eric
6
Oui mais non. Je pense qu'il veut avoir le nombre de NULL et non de NULL en une seule requête ... Vous dites comment faire cela en deux requêtes ...
Romain Linsolas
@romaintaz: C'est vrai. J'ai lu le titre comme la question. En cinq modifications, personne n'a pensé à le réparer. Yeesh.
Eric
@romaintaz: Oui, vous avez raison, j'ai pris cela comme une "requête exécutée une fois pour repérer le nombre de valeurs nulles que nous avons", je ne sais même pas pourquoi ^^ ', je vais corriger, merci.
Alberto Zaccagni
1
@Montecristo: Parce que le titre ne demandait qu'à compter null:)
Eric
42

Voici une version rapide et sale qui fonctionne sur 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
la source
3
Une syntaxe similaire fonctionnerait également dans SQL Server. De plus, en procédant de cette manière, la table ne sera analysée qu'une seule fois; les solutions UNION effectueront deux analyses de table. Peu pertinent pour les petites tables, très important pour les grandes.
Philip Kelley
2
Seul changement pour SQL Server "Null values"devrait devenir 'Null values'. Guillemets simples, pas doubles.
Eric
1
SQLServer utilise une analyse d'index pour cette requête par rapport à deux recherches d'index à l' aide d'une union. Sur une table de 40 000 lignes, il n'y a pas de différence de vitesse.
Lieven Keersmaekers
1
Sur une table avec 11.332.581 lignes, il y a deux balayages de table , pas de différence de vitesse notable (en fait, l'union est légèrement plus rapide).
Lieven Keersmaekers
1
Cela n'a pas fonctionné pour moi dans Oracle 11g. La version @ user155789 publiée avec "case when a is null then 1 else 0 end" était la syntaxe qui fonctionnait.
Steve
25

Comme j'ai compris votre requête, exécutez simplement ce script et obtenez Total Null, Total NotNull,

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

pour les non nuls

select count(a)
from us

pour les nuls

select count(*)
from us

minus 

select count(a)
from us

Par conséquent

SELECT COUNT(A) NOT_NULLS
FROM US

UNION

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

devrait faire le travail

Mieux, les titres des colonnes sont corrects.

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

Dans certains tests sur mon système, cela coûte une analyse complète de la table.

EvilTeach
la source
4
Bonne sauce, mec, regardez les plans d'exécution de ces requêtes. Vous lancez des scans de table à gauche et à droite, en particulier là où il y a une déclaration si simple ( select count(*) from t where a is null) qui fait cela.
Eric
2
Je n'ai pas de base de données à portée de main, mais la colonne est indexée ou non. Si c'est le cas, cela se produit via une analyse de plage, sinon, vous vous retrouvez à peu près avec une analyse complète de la table. Dans oracle, les NULL ne sont pas stockés dans l'index, donc je suppose que votre exemple n'est pas beaucoup mieux. Votre kilométrage peut très bien.
EvilTeach
1
@EvilTeach: les index ne sont utiles que lorsque vous ne retirez pas> ~ 10% des lignes. Après cela, des analyses complètes sont lancées. Dans ce cas, vous obtiendrez l'analyse au moins une fois, sinon deux fois.
Eric
19

habituellement j'utilise cette astuce

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
la source
6

C'est peu compliqué. Supposons que la table ne comporte qu'une seule colonne, puis le nombre (1) et le nombre (*) donneront des valeurs différentes.

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

Résultats de la requête

Comme vous pouvez le voir sur l'image, le premier résultat montre que le tableau comporte 16 lignes. dont deux lignes sont NULL. Ainsi, lorsque nous utilisons Count (*), le moteur de requête compte le nombre de lignes, donc nous avons obtenu le résultat de count comme 16. Mais dans le cas de Count (empid), il a compté les valeurs non NULL dans la colonne empid . Nous avons donc obtenu le résultat 14.

donc chaque fois que nous utilisons COUNT (Colonne), assurez-vous que nous prenons soin des valeurs NULL comme indiqué ci-dessous.

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

comptera les valeurs NULL et Non-NULL.

Remarque : la même chose s'applique même lorsque le tableau est composé de plus d'une colonne. Count (1) donnera le nombre total de lignes indépendamment des valeurs NULL / Non-NULL. Ce n'est que lorsque les valeurs de colonne sont comptées à l'aide de Count (Column) que nous devons prendre soin des valeurs NULL.

Santhoshkumar LM
la source
4

J'ai eu un problème similaire: compter toutes les valeurs distinctes, en comptant également les valeurs nulles comme 1. Un simple décompte ne fonctionne pas dans ce cas, car il ne prend pas en compte les valeurs nulles.

Voici un extrait de code qui fonctionne sur SQL et n'implique pas de sélection de nouvelles valeurs. Fondamentalement, une fois effectué le distinct, renvoyez également le numéro de ligne dans une nouvelle colonne (n) en utilisant la fonction row_number (), puis effectuez un comptage sur cette colonne:

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

Voici deux solutions:

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
la source
3

Essayer

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

Facile!

Rodrigo Prazim
la source
3

Essaye ça..

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
la source
2

Si vous utilisez 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;

Je ne vous recommande pas de faire cela ... mais vous l'avez ici (dans le même tableau que le résultat)

Andrei
la source
2

utiliser la fonction intégrée ISNULL.


Serget
la source
C'est aussi une bonne réponse. J'ai personnellement trouvé que COUNT (DISTINCT ISNULL (A, '')) fonctionne encore mieux que COUNT (DISTINCT A) + SUM (CASE WHEN A IS NULL PUIS 1 ELSE 0 END)
Vladislav
1

si c'est mysql, vous pouvez essayer quelque chose comme ça.

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

C'est fugace, mais il renverra un seul enregistrement avec 2 cols indiquant le nombre de nuls par rapport aux non nuls.

Gourou C-Pound
la source
1

Cela fonctionne dans T-SQL. Si vous comptez simplement le nombre de quelque chose et que vous souhaitez inclure les valeurs nulles, utilisez COALESCE au lieu de case.

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
la source
1

En m'appuyant sur Alberto, j'ai ajouté le rollup.

 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
la source
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
la source
1
select count(isnull(NullableColumn,-1))
Imran Shamszadeh
la source
2
Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire concernant la raison et / ou la manière dont ce code répond à la question améliore sa valeur à long terme.
Vishal Chhodwani
1

Toutes les réponses sont soit fausses, soit extrêmement dépassées.

La manière simple et correcte de faire cette requête est d'utiliser la COUNT_IFfonction.

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

Juste au cas où vous le vouliez dans un seul enregistrement:

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

;-)

Sparhawk_
la source
0

pour compter des valeurs non nulles

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

pour compter les valeurs nulles

 select count(*) from us where a is null;
Shah profond
la source
1
L'op a demandé une seule requête :)
infografnet
0

J'ai créé la table dans postgres 10 et les deux ont fonctionné:

select count(*) from us

et

select count(a is null) from us

skrillybrick
la source
a IS NULLproduit TRUEou FALSE, et COUNT () comptera toutes les valeurs NOT NULL. Donc count(a is null)retournera le nombre de toutes les lignes.
ypresto
0

Dans mon cas, je voulais la " distribution nulle " entre plusieurs colonnes:

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

Selon le '...', il est facilement extensible à plus de colonnes, autant que nécessaire

Vzzarr
la source
-1

Nombre d'éléments où a est nul:

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

Nombre d'éléments où a n'est pas nul:

select count(a) from us where a is not null;
Romain Linsolas
la source
1
La question est pour une seule requête.
DreamWave