31

I have 3 columns let say A, B, and C. I need to count the NULL values in each column.

For example:

 A  | B  | C
-------------
1   |NULL| 1
1   | 1  | NULL
NULL| 1  | 1
NULL|NULL| 1

Should output:

 A  |  B  |  C
---------------
 2  |  2  |  1

I've tried count, sum, sub-queries but nothing has worked for me yet. Any input would be appreciated!

1
  • 1
    What is your RDBMS (SQL flavor)? Commented May 13, 2013 at 18:28

6 Answers 6

53
SELECT COUNT(*)-COUNT(A) As A, COUNT(*)-COUNT(B) As B, COUNT(*)-COUNT(C) As C
FROM YourTable; 
Sign up to request clarification or add additional context in comments.

2 Comments

Is there a way to do this if the table has many columns and I don't want to explicitly write them all out?
If you are using dbt in your stack, a macro can be created to write this query for you programmatically. Making this note as this tool is now commonplace in data stack. You can incorporate use of the star macro or one of the utils that it relies on to get column names to pass in, as shared in this answer on getting column names via dbt. Granted, you would still need to run the compiled code to determine the null counts, if you're doing this ad hoc, otherwise you could materialize the a null counts table on a schedule.
12

For SQL SERVER you can use the following:

SET NOCOUNT ON
DECLARE @Schema NVARCHAR(100) = '<Your Schema>'
DECLARE @Table NVARCHAR(100) = '<Your Table>'
DECLARE @sql NVARCHAR(MAX) =''
IF OBJECT_ID ('tempdb..#Nulls') IS NOT NULL DROP TABLE #Nulls

CREATE TABLE #Nulls (TableName sysname, ColumnName sysname , ColumnPosition int ,NullCount int , NonNullCount int)

 SELECT @sql += 'SELECT  '''+TABLE_NAME+''' AS TableName , '''+COLUMN_NAME+''' AS ColumnName,  '''+CONVERT(VARCHAR(5),ORDINAL_POSITION)+''' AS ColumnPosition, SUM(CASE WHEN '+COLUMN_NAME+' IS NULL THEN 1 ELSE 0 END) CountNulls , COUNT(' +COLUMN_NAME+') CountnonNulls FROM '+QUOTENAME(TABLE_SCHEMA)+'.'+QUOTENAME(TABLE_NAME)+';'+ CHAR(10)
 FROM INFORMATION_SCHEMA.COLUMNS
 WHERE TABLE_SCHEMA = @Schema
 AND TABLE_NAME = @Table

 INSERT INTO #Nulls 
 EXEC sp_executesql @sql

 SELECT * 
 FROM #Nulls

 DROP TABLE #Nulls

you will receive a result set with the count of Null values and non null values in each column of you table

1 Comment

This answer is great, though be aware that COLUMN_NAME isn't quoted, so would be improved by substituting QUOTENAME(COLUMN_NAME) to support column names with spaces, reserved words etc. (Would make the change myself but the edit queue is full)
10

You can use an aggregate function with a CASE expression:

select 
  sum(case when a is null then 1 else 0 end) A,
  sum(case when b is null then 1 else 0 end) B,
  sum(case when c is null then 1 else 0 end) C
from yt

See Demo

3 Comments

@Matthew Not necessary, NULL sums as 0.
@JoachimIsaksson really? 1+NULL = 0? I guess I haven't checked in a while.
Thanks! Funny I had typed that out and was going to try that when I got back to work, but I figured I'd still ask. If I would have known about the site you did the Demo on I could have tested it myself. Thanks!
4
SELECT
(SELECT count(*) FROM my_table WHERE A is NULL) as A,
(SELECT count(*) FROM my_table WHERE B is NULL) as B,
(SELECT count(*) FROM my_table WHERE C is NULL) as C

Comments

4
select
    sum(case when a is null then 1 else 0 end) as a_null_count,
    sum(case when b is null then 1 else 0 end) as b_null_count,
    sum(case when c is null then 1 else 0 end) as c_null_count
from table

Comments

1

I am very late to this, but if you don't want to manually list out all the column names and still want to get a table, you can do this in SQL Server (Just replace testTable with your actual table):

--Creates the table the poster wanted

CREATE TABLE testTable (A int, B int, C int)
INSERT INTO testTable (A, C) VALUES (1,1)
INSERT INTO testTable (A, B) VALUES (1,1)
INSERT INTO testTable (B, C) VALUES (1,1)
INSERT INTO testTable (C) VALUES (1)

--Creates the output table which will consist of each column name and the amount of nulls

CREATE TABLE ColumnNames (
    ID int IDENTITY(1,1) PRIMARY KEY,
    [name] varchar(max),
    nullAmount int
)

INSERT INTO ColumnNames ([name]) 
SELECT [name] FROM sys.columns WHERE object_id = OBJECT_ID('dbo.testTable')

DECLARE @columnIndex INT = 1

WHILE @columnIndex <= ( SELECT COUNT(*) FROM dbo.ColumnNames )
BEGIN
    DECLARE @colName nvarchar(max) = (SELECT [name] FROM ColumnNames WHERE ID = @columnIndex)
    EXEC('SELECT ' + @colName + ' INTO colTable FROM testTable')

    DECLARE @SQL nvarchar(max) = N'UPDATE ColumnNames SET nullAmount = (SELECT COUNT(1) - COUNT(' + quotename(@colName) + ') FROM colTable) WHERE ID = @columnIndex'
    EXEC SP_EXECUTESQL @SQL, N'@columnIndex int', @columnIndex 

    DROP TABLE colTable
    SET @columnIndex = @columnIndex + 1
END

--Select the output table and get null info
SELECT * FROM ColumnNames

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.