Counting null and non-null values in a single query - sql

I have a table
create table us
(
a number
);
Now I have data like:
a
1
2
3
4
null
null
null
8
9
Now I need a single query to count null and not null values in column a

This works for Oracle and SQL Server (you might be able to get it to work on another RDBMS):
select sum(case when a is null then 1 else 0 end) count_nulls
, count(a) count_not_nulls
from us;
Or:
select count(*) - count(a), count(a) from us;

If I understood correctly you want to count all NULL and all NOT NULL in a column...
If that is correct:
SELECT count(*) FROM us WHERE a IS NULL
UNION ALL
SELECT count(*) FROM us WHERE a IS NOT NULL
Edited to have the full query, after reading the comments :]
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;

Here is a quick and dirty version that works on 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

for non nulls
select count(a)
from us
for nulls
select count(*)
from us
minus
select count(a)
from us
Hence
SELECT COUNT(A) NOT_NULLS
FROM US
UNION
SELECT COUNT(*) - COUNT(A) NULLS
FROM US
ought to do the job
Better in that the column titles come out correct.
SELECT COUNT(A) NOT_NULL, COUNT(*) - COUNT(A) NULLS
FROM US
In some testing on my system, it costs a full table scan.

As i understood your query, You just run this script and get Total Null,Total NotNull rows,
select count(*) - count(a) as 'Null', count(a) as 'Not Null' from us;

usually i use this trick
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

Just to provide yet another alternative, Postgres 9.4+ allows applying a FILTER to aggregates:
SELECT
COUNT(*) FILTER (WHERE a IS NULL) count_nulls,
COUNT(*) FILTER (WHERE a IS NOT NULL) count_not_nulls
FROM us;
SQLFiddle: http://sqlfiddle.com/#!17/80a24/5

This is little tricky. Assume the table has just one column, then the Count(1) and Count(*) will give different values.
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
Query Results
As you can see in the image, The first result shows the table has 16 rows. out of which two rows are NULL. So when we use Count(*) the query engine counts the number of rows, So we got count result as 16. But in case of Count(empid) it counted the non-NULL-values in the column empid. So we got the result as 14.
so whenever we are using COUNT(Column) make sure we take care of NULL values as shown below.
select COUNT(isnull(empid,1)) from #table1
will count both NULL and Non-NULL values.
Note: Same thing applies even when the table is made up of more than one column. Count(1) will give total number of rows irrespective of NULL/Non-NULL values. Only when the column values are counted using Count(Column) we need to take care of NULL values.

I had a similar issue: to count all distinct values, counting null values as 1, too. A simple count doesn't work in this case, as it does not take null values into account.
Here's a snippet that works on SQL and does not involve selection of new values.
Basically, once performed the distinct, also return the row number in a new column (n) using the row_number() function, then perform a count on that column:
SELECT COUNT(n)
FROM (
SELECT *, row_number() OVER (ORDER BY [MyColumn] ASC) n
FROM (
SELECT DISTINCT [MyColumn]
FROM [MyTable]
) items
) distinctItems

Try this..
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

Here are two solutions:
Select count(columnname) as countofNotNulls, count(isnull(columnname,1))-count(columnname) AS Countofnulls from table name
OR
Select count(columnname) as countofNotNulls, count(*)-count(columnname) AS Countofnulls from table name

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

If you're using 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;
I don't recomend you doing this... but here you have it (in the same table as result)

use ISNULL embedded function.

All the answers are either wrong or extremely out of date.
The simple and correct way of doing this query is using COUNT_IF function.
SELECT
COUNT_IF(a IS NULL) AS nulls,
COUNT_IF(a IS NOT NULL) AS not_nulls
FROM
us

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
It's fugly, but it will return a single record with 2 cols indicating the count of nulls vs non nulls.

This works in T-SQL. If you're just counting the number of something and you want to include the nulls, use COALESCE instead of 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')

Building off of Alberto, I added the 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;

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

select count(isnull(NullableColumn,-1))

if its mysql, you can try something like this.
select
(select count(*) from TABLENAME WHERE a = 'null') as total_null,
(select count(*) from TABLENAME WHERE a != 'null') as total_not_null
FROM TABLENAME

Just in case you wanted it in a single record:
select
(select count(*) from tbl where colName is null) Nulls,
(select count(*) from tbl where colName is not null) NonNulls
;-)

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

I created the table in postgres 10 and both of the following worked:
select count(*) from us
and
select count(a is null) from us

In my case I wanted the "null distribution" amongst multiple columns:
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,...
As per the '...' it is easily extendable to more columns, as many as needed

Number of elements where a is null:
select count(a) from us where a is null;
Number of elements where a is not null:
select count(a) from us where a is not null;

Related

Is there a way to return all unique values within a given row

I am working in Oracle SQL and I have a data set with these headers
In this data set card number is unique, however, the customer can have duplicates in their Suggestion fields. Rather than going through and writing case statements, is there a way to keep only the unique values within the given row?
Please note, some customers will be left with more "unique" suggestions than others
For example:
My goal would be for my final output to look like this
As I have mentioned, previously, I would just write case statements saying
SELECT DISTINCT CARD_NUMBER
,SUGGESTION_1
,CASE
WHEN SUGGESTION_2 != SUGGESTION_1
THEN SUGGESTION_2
WHEN SUGGESTION_3 != SUGGESTION_1
THEN SUGGESTION_3
WHEN SUGGESTION_4 != SUGGESTION_1
THEN SUGGESTION_4
WHEN SUGGESTION_5 != SUGGESTION_1
THEN SUGGESTION_5
END AS SUGGESTION_2
CASE
WHEN SUGGESTION_2 != SUGGESTION_1
AND SUGGESTION_3 != SUGGESTION_1
AND SUGGESTION_3 != SUGGESTION_2
THEN SUGGESTION_3
`
I would do this until all unique values are left, and there just has to be an easier way
Any help would be EXTREMELY appreciated, thank you!
You can use union all and conditional aggregation. Here is the idea that puts the results in a single column:
select card, listagg(suggestion, ', ') within group (order by which) as suggestions
from (select card, suggestion, min(which) as which
from ((select card, 1 as which, suggestion_1 as suggestion from t) union all
(select card, 2, suggestion_2 from t) union all
(select card, 3, suggestion_3 from t) union all
(select card, 4, suggestion_4 from t) union all
(select card, 5, suggestion_5 from t)
) t
group by card, suggestion
) t
group by card;
You can do something similar with conditional aggregation if you want the values in separate columns.
I would try to pivot the table to long, and then back to wide
Setup:
create table testtbl
(
CARD_NUMBER int
,SUGGESTION_1 varchar2(100)
,SUGGESTION_2 varchar2(100)
,SUGGESTION_3 varchar2(100)
,SUGGESTION_4 varchar2(100)
,SUGGESTION_5 varchar2(100)
);
insert into testtbl values (1234,'G11','G4','G3','G2','G6');
insert into testtbl values (5678,'G4','G6','G6','G11','G6');
insert into testtbl values (9101,'G1','G3','G11','G4','G11');
Then the Query itself, first the pivoting to long. Here I use a function just to return the numbers from 1 to 5 - this is instead of joining the table 5 times to itself, this way it should only pass through the test table once.
I then use the analytical functionrow_number to sort the unique values according to their first placement.
The second select uses MAX to pivot back to wide
with cte AS
(
SELECT
CARD_NUMBER
,MIN(n.column_value ) n
,CASE n.column_value
WHEN 1 THEN f.SUGGESTION_1
WHEN 2 THEN f.SUGGESTION_2
WHEN 3 THEN f.SUGGESTION_3
WHEN 4 THEN f.SUGGESTION_4
WHEN 5 THEN f.SUGGESTION_5
END Suggestion
,ROW_NUMBER() OVER (PARTITION BY f.CARD_NUMBER ORDER BY MIN(n.column_value)) rn
FROM testtbl f
CROSS JOIN table(sys.odcinumberlist(1,2,3,4,5)) n
GROUP BY f.CARD_NUMBER,CASE n.column_value
WHEN 1 THEN f.SUGGESTION_1
WHEN 2 THEN f.SUGGESTION_2
WHEN 3 THEN f.SUGGESTION_3
WHEN 4 THEN f.SUGGESTION_4
WHEN 5 THEN f.SUGGESTION_5
END
)
SELECT
CARD_NUMBER
,MAX(CASE WHEN rn=1 THEN Suggestion ELSE '' end)SUGGESTION_1
,MAX(CASE WHEN rn=2 THEN Suggestion ELSE '' end)SUGGESTION_2
,MAX(CASE WHEN rn=3 THEN Suggestion ELSE '' end)SUGGESTION_3
,MAX(CASE WHEN rn=4 THEN Suggestion ELSE '' end)SUGGESTION_4
,MAX(CASE WHEN rn=5 THEN Suggestion ELSE '' end)SUGGESTION_5
FROM cte
GROUP BY CARD_NUMBER
ORDER BY CARD_NUMBER

SQL code to count only duplicates where all instances of the duplicate are null

I have a large data set with duplicate reference numbers (reference duplications range from 0 to 37 times). I want to count the number of references only where all instances are null in two columns. So using the table below, the code should return 1 because only Reference Code 3 has all null values, and the duplicates should only be counted once.
I would be grateful for any help.
This involves two steps: (1) isolate all the distinct pairs of values that only have null; (2) count each one once. One way to express this in a query is:
SELECT COUNT(*) FROM
(
SELECT refnum FROM #ref
GROUP BY refnum
HAVING MIN(colA) IS NULL
AND MIN(colB) IS NULL;
) AS x;
Use aggregation to get the codes:
select code
from t
group by code
having max(a) is null and max(b) is null;
If you want the count, use a subquery:
select count(*)
from (select code
from t
group by code
having max(a) is null and max(b) is null
) t;
With conditional aggregation:
select
refcode
from referencecodes
group by refcode
having sum(case when (a is null and b is null) then 0 else 1 end) = 0
The above will return the codes with only null values in a and b.
If you want the number of codes:
select count(r.refcode) from (
select
refcode
from referencecodes
group by refcode
having sum(case when (a is null and b is null) then 0 else 1 end) = 0
) r
Or with EXISTS:
select
count(distinct r.refcode)
from referencecodes r
where not exists (
select 1 from referencecodes
where (refcode = r.refcode) and (a is not null or b is not null)
)
See the demo

Oracle case when NOT null?

I see a lot of queries made for Oracle using CASE columnX WHEN NULL
how to design query if
CASE columnX WHEN NOT NULL ?
SQL developer throws an error on the query so how to make condition query using CASE... WHEN...?
WITH dates_list AS
(SELECT TO_DATE('02-19-2018','MM-dd-yyyy') + ROWNUM - 1 AS DAY,
rownum AS row_num
FROM dual
CONNECT BY LEVEL <= (TO_DATE('03-29-2018','MM-dd-yyyy') - TO_DATE('02-19-2018','MM-dd-yyyy')+1)
)
SELECT dates1.day, dates2.*, count(case dates2.day when null then 1 else 0 end)
over (partition by dates2.day order by dates1.day) as cnt
FROM dates_list dates1
LEFT JOIN
(SELECT *
FROM dates_list
WHERE TO_CHAR(DAY,'D') NOT IN (7,1)
) dates2 ON dates1.day = dates2.day
ORDER BY dates1.day;
above query gives error when I change when null to when not null
You can't use the CASE sentence in that way with NULL values, because columnX is never "equal" to NULL. You should use instead:
CASE WHEN columnX IS NULL THEN
or
CASE WHEN columnX IS NOT NULL THEN
You now have a function NVL that can turn this:
CASE WHEN columnX IS NOT NULL THEN columnX ELSE 'No value' END
Into this:
NVL(columnX, 'No value')
If columnX is a select, it make everything a lot cleaner

Is it possible to specify condition in Count()?

Is it possible to specify a condition in Count()? I would like to count only the rows that have, for example, "Manager" in the Position column.
I want to do it in the count statement, not using WHERE; I'm asking about it because I need to count both Managers and Other in the same SELECT (something like Count(Position = Manager), Count(Position = Other)) so WHERE is no use for me in this example.
If you can't just limit the query itself with a where clause, you can use the fact that the count aggregate only counts the non-null values:
select count(case Position when 'Manager' then 1 else null end)
from ...
You can also use the sum aggregate in a similar way:
select sum(case Position when 'Manager' then 1 else 0 end)
from ...
Assuming you do not want to restrict the rows that are returned because you are aggregating other values as well, you can do it like this:
select count(case when Position = 'Manager' then 1 else null end) as ManagerCount
from ...
Let's say within the same column you had values of Manager, Supervisor, and Team Lead, you could get the counts of each like this:
select count(case when Position = 'Manager' then 1 else null end) as ManagerCount,
count(case when Position = 'Supervisor' then 1 else null end) as SupervisorCount,
count(case when Position = 'Team Lead' then 1 else null end) as TeamLeadCount,
from ...
#Guffa 's answer is excellent, just point out that maybe is cleaner with an IF statement
select count(IIF(Position = 'Manager', 1, NULL)) as ManagerCount
from ...
Depends what you mean, but the other interpretation of the meaning is where you want to count rows with a certain value, but don't want to restrict the SELECT to JUST those rows...
You'd do it using SUM() with a clause in, like this instead of using COUNT():
e.g.
SELECT SUM(CASE WHEN Position = 'Manager' THEN 1 ELSE 0 END) AS ManagerCount,
SUM(CASE WHEN Position = 'CEO' THEN 1 ELSE 0 END) AS CEOCount
FROM SomeTable
If using Postgres or SQLite, you can use the Filter clause to improve readability:
SELECT
COUNT(1) FILTER (WHERE POSITION = 'Manager') AS ManagerCount,
COUNT(1) FILTER (WHERE POSITION = 'Other') AS OtherCount
FROM ...
BigQuery also has Countif - see the support across different SQL dialects for these features here:
https://modern-sql.com/feature/filter
You can also use the Pivot Keyword if you are using SQL 2005 or above
more info and from Technet
SELECT *
FROM #Users
PIVOT (
COUNT(Position)
FOR Position
IN (Manager, CEO, Employee)
) as p
Test Data Set
DECLARE #Users TABLE (Position VARCHAR(10))
INSERT INTO #Users (Position) VALUES('Manager')
INSERT INTO #Users (Position) VALUES('Manager')
INSERT INTO #Users (Position) VALUES('Manager')
INSERT INTO #Users (Position) VALUES('CEO')
INSERT INTO #Users (Position) VALUES('Employee')
INSERT INTO #Users (Position) VALUES('Employee')
INSERT INTO #Users (Position) VALUES('Employee')
INSERT INTO #Users (Position) VALUES('Employee')
INSERT INTO #Users (Position) VALUES('Employee')
INSERT INTO #Users (Position) VALUES('Employee')
Do you mean just this:
SELECT Count(*) FROM YourTable WHERE Position = 'Manager'
If so, then yup that works!
I know this is really old, but I like the NULLIF trick for such scenarios, and I found no downsides so far. Just see my copy&pasteable example, which is not very practical though, but demonstrates how to use it.
NULLIF might give you a small negative impact on performance, but I guess it should still be faster than subqueries.
DECLARE #tbl TABLE ( id [int] NOT NULL, field [varchar](50) NOT NULL)
INSERT INTO #tbl (id, field)
SELECT 1, 'Manager'
UNION SELECT 2, 'Manager'
UNION SELECT 3, 'Customer'
UNION SELECT 4, 'Boss'
UNION SELECT 5, 'Intern'
UNION SELECT 6, 'Customer'
UNION SELECT 7, 'Customer'
UNION SELECT 8, 'Wife'
UNION SELECT 9, 'Son'
SELECT * FROM #tbl
SELECT
COUNT(1) AS [total]
,COUNT(1) - COUNT(NULLIF([field], 'Manager')) AS [Managers]
,COUNT(NULLIF([field], 'Manager')) AS [NotManagers]
,(COUNT(1) - COUNT(NULLIF([field], 'Wife'))) + (COUNT(1) - COUNT(NULLIF([field], 'Son'))) AS [Family]
FROM #tbl
Comments appreciated :-)
Here is what I did to get a data set that included both the total and the number that met the criteria, within each shipping container. That let me answer the question "How many shipping containers have more than X% items over size 51"
select
Schedule,
PackageNum,
COUNT (UniqueID) as Total,
SUM (
case
when
Size > 51
then
1
else
0
end
) as NumOverSize
from
Inventory
where
customer like '%PEPSI%'
group by
Schedule, PackageNum
Note with PrestoDB SQL (from Facebook), there is a shortcut:
https://prestodb.io/docs/current/functions/aggregate.html
count_if(x) → bigint
Returns the number of TRUE input values. This
function is equivalent to count(CASE WHEN x THEN 1 END)
SELECT COUNT(*) FROM bla WHERE Position = 'Manager'
In MySQL, boolean expressions evaluate to 0 or 1, so the following aggregation works:
select sum(Position = 'Manager') as ManagerCount
from ...
I think you can use a simple WHERE clause to select only the count some record.

How do I return my records grouped by NULL and NOT NULL?

I have a table that has a processed_timestamp column -- if a record has been processed then that field contains the datetime it was processed, otherwise it is null.
I want to write a query that returns two rows:
NULL xx -- count of records with null timestamps
NOT NULL yy -- count of records with non-null timestamps
Is that possible?
Update: The table is quite large, so efficiency is important. I could just run two queries to calculate each total separately, but I want to avoid hitting the table twice if I can avoid it.
In MySQL you could do something like
SELECT
IF(ISNULL(processed_timestamp), 'NULL', 'NOT NULL') as myfield,
COUNT(*)
FROM mytable
GROUP BY myfield
In T-SQL (MS SQL Server), this works:
SELECT
CASE WHEN Field IS NULL THEN 'NULL' ELSE 'NOT NULL' END FieldContent,
COUNT(*) FieldCount
FROM
TheTable
GROUP BY
CASE WHEN Field IS NULL THEN 'NULL' ELSE 'NOT NULL' END
Oracle:
group by nvl2(field, 'NOT NULL', 'NULL')
Try the following, it's vendor-neutral:
select
'null ' as type,
count(*) as quant
from tbl
where tmstmp is null
union all
select
'not null' as type,
count(*) as quant
from tbl
where tmstmp is not null
After having our local DB2 guru look at this, he concurs: none of the solutions presented to date (including this one) can avoid a full table scan (of the table if timestamp is not indexed, or of the indexotherwise). They all scan every record in the table exactly once.
All the CASE/IF/NVL2() solutions do a null-to-string conversion for each row, introducing unnecessary load on the DBMS. This solution does not have that problem.
Stewart,
Maybe consider this solution. It is (also!) vendor non-specific.
SELECT count([processed_timestamp]) AS notnullrows,
count(*) - count([processed_timestamp]) AS nullrows
FROM table
As for efficiency, this avoids 2x index seeks/table scans/whatever by including the results on one row. If you absolutely require 2 rows in the result, two passes over the set may be unavoidable because of unioning aggregates.
Hope this helps
If it's oracle then you can do:
select decode(field,NULL,'NULL','NOT NULL'), count(*)
from table
group by decode(field,NULL,'NULL','NOT NULL');
I'm sure that other DBs allow for similar trick.
Another MySQL method is to use the CASE operator, which can be generalised to more alternatives than IF():
SELECT CASE WHEN processed_timestamp IS NULL THEN 'NULL'
ELSE 'NOT NULL' END AS a,
COUNT(*) AS n
FROM logs
GROUP BY a
SQL Server (starting with 2012):
SELECT IIF(ISDATE(processed_timestamp) = 0, 'NULL', 'NON NULL'), COUNT(*)
FROM MyTable
GROUP BY ISDATE(processed_timestamp);
Another way in T-sql (sql-server)
select count(case when t.timestamps is null
then 1
else null end) NULLROWS,
count(case when t.timestamps is not null
then 1
else null end) NOTNULLROWS
from myTable t
If your database has an efficient COUNT(*) function for a table, you could COUNT whichever is the smaller number, and subtract.
In Oracle
SELECT COUNT(*), COUNT(TIME_STAMP_COLUMN)
FROM TABLE;
count(*) returns the count of all rows
count(column_name) returns the number of rows which are not NULL, so
SELECT COUNT(*) - COUNT(TIME_STAMP_COLUMN) NUL_COUNT,
COUNT(TIME_STAMP_COLUMN) NON_NUL_COUNT
FROM TABLE
ought to do the job.
If the column is indexed, you might end up with some sort of range scan and avoid actually reading the table.
I personally like Pax's solution, but if you absolutely require only one row returned (as I had recently), In MS SQL Server 2005/2008 you can "stack" the two queries using a CTE
with NullRows (countOf)
AS
(
SELECT count(*)
FORM table
WHERE [processed_timestamp] IS NOT NULL
)
SELECT count(*) AS nulls, countOf
FROM table, NullRows
WHERE [processed_timestamp] IS NULL
GROUP BY countOf
Hope this helps
[T-SQL]:
select [case], count(*) tally
from (
select
case when [processed_timestamp] is null then 'null'
else 'not null'
end [case]
from myTable
) a
And you can add into the case statement whatever other values you'd like to form a partition, e.g. today, yesterday, between noon and 2pm, after 6pm on a Thursday.
Select Sum(Case When processed_timestamp IS NULL
Then 1
Else 0
End) not_processed_count,
Sum(Case When processed_timestamp Is Not NULL
Then 1
Else 0
End) processed_count,
Count(1) total
From table
Edit: didn't read carefully, this one returns a single row.