如何返回按 NULL 和 NOT NULL 分组的记录?

我有一个包含 processed_timestamp列的表——如果一条记录已被处理,那么该字段包含已被处理的日期时间,否则为 null。

我想编写一个返回两行的查询:

NULL        xx -- count of records with null timestamps
NOT NULL    yy -- count of records with non-null timestamps

这可能吗?

更新: 该表非常大,因此效率非常重要。我可以分别运行两个查询来计算每个总数,但是如果可以避免的话,我希望避免两次碰到表。

60328 次浏览

在 MySQL 中,你可以这样做

SELECT
IF(ISNULL(processed_timestamp), 'NULL', 'NOT NULL') as myfield,
COUNT(*)
FROM mytable
GROUP BY myfield

如果是甲骨文,你可以这样做:

select decode(field,NULL,'NULL','NOT NULL'), count(*)
from table
group by decode(field,NULL,'NULL','NOT NULL');

我相信其他的尸体也有类似的技巧。

试试下面的方法,它与供应商无关:

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

在让我们的本地 DB2专家研究了这个问题之后,他表示同意: 迄今为止提出的所有解决方案(包括这个)都不能避免完整的表扫描(如果时间戳没有被索引,则扫描表,或者扫描索引)。他们只扫描一次表中的所有记录。

所有的 CASE/IF/NVL2()解决方案都为每一行执行空字符串转换,从而给 DBMS 带来不必要的负载。这个解决方案没有这个问题。

甲骨文:

Group by nvl2(字段,‘ NOT NULL’,‘ NULL’)

在 T-SQL (MS SQL Server)中,这种方法是有效的:

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

另一种 MySQL 方法是使用 CASE接线员,它可以推广到比 IF()更多的选择:

SELECT CASE WHEN processed_timestamp IS NULL THEN 'NULL'
ELSE 'NOT NULL' END AS a,
COUNT(*) AS n
FROM logs
GROUP BY a

我个人喜欢 Pax 的解决方案,但是如果您绝对只需要返回一行(就像我最近所做的那样) ,那么在 MS SQL Server 2005/2008中,您可以使用 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

希望这个能帮上忙

[ T-SQL ] :

select [case], count(*) tally
from (
select
case when [processed_timestamp] is null then 'null'
else 'not null'
end [case]
from myTable
) a

你可以在 case 语句中添加任何你想要形成分区的值,比如今天,昨天,中午到下午2点,周四下午6点之后。

斯图尔特,

也许可以考虑这个解决方案。它是(也!)供应商非特定的。

SELECT count([processed_timestamp]) AS notnullrows,
count(*) - count([processed_timestamp]) AS nullrows
FROM table

至于效率,通过在一行中包含结果,可以避免2x 索引查找/表扫描/无论什么。如果您在结果中绝对需要两行,那么由于联合聚合,在集合上进行两次传递可能是不可避免的。

希望这个能帮上忙

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

编辑: 没有仔细阅读,这个返回一行。

在甲骨文

SELECT COUNT(*), COUNT(TIME_STAMP_COLUMN)
FROM TABLE;

Count (*)返回所有行的计数

Count (column _ name)返回不为 NULL 的行数,因此

SELECT COUNT(*) - COUNT(TIME_STAMP_COLUMN) NUL_COUNT,
COUNT(TIME_STAMP_COLUMN) NON_NUL_COUNT
FROM TABLE

应该可以完成任务。

如果对列进行了索引,那么最终可能会进行某种范围扫描,从而避免实际读取表。

如果您的数据库对表有一个高效的 COUNT (*)函数,那么您可以使用较小的数字 COUNT,然后进行减法。

SQLServer (从2012年开始) :

SELECT IIF(ISDATE(processed_timestamp) = 0, 'NULL', 'NON NULL'), COUNT(*)
FROM MyTable
GROUP BY ISDATE(processed_timestamp);

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