Como faço para retornar meus registros agrupados por NULL e NOT NULL?
Pergunta
Eu tenho uma tabela que tem uma coluna processed_timestamp
- se um registro foi processado depois que o campo contém a data e hora que foi processado, caso contrário é nula
Eu quero escrever uma consulta que retorna duas linhas:
NULL xx -- count of records with null timestamps
NOT NULL yy -- count of records with non-null timestamps
É possível?
Update: A tabela é muito grande, por isso a eficiência é importante. Eu poderia simplesmente executar duas consultas para calcular o total de cada separadamente, mas eu quero evitar bater na mesa duas vezes se eu puder evitá-lo.
Solução
Oracle:
grupo por NVL2 (campo, 'NOT NULL', 'NULL')
Outras dicas
No MySQL você pode fazer algo como
SELECT
IF(ISNULL(processed_timestamp), 'NULL', 'NOT NULL') as myfield,
COUNT(*)
FROM mytable
GROUP BY myfield
Na T-SQL (MS SQL Server), isso funciona:
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
Tente o seguinte, é 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
Depois de ter nosso olhar DB2 guru local a isso, ele concorda: nenhuma das soluções apresentadas até à data (incluindo este) pode evitar uma varredura completa da tabela (da tabela se timestamp não está indexado, ou do indexotherwise). Todos eles varredura de cada registro na tabela exatamente uma vez.
Toda a CASE / SE / NVL2 () soluções fazer uma conversão nula-to-string para cada linha, introduzindo carga desnecessária sobre os DBMS. Esta solução não tem esse problema.
Se da Oracle, em seguida, você pode fazer:
select decode(field,NULL,'NULL','NOT NULL'), count(*)
from table
group by decode(field,NULL,'NULL','NOT NULL');
Estou certo de que outros bancos de dados permitem truque similar.
Stewart,
Talvez considerar esta solução. É (também!) Não-específico do fornecedor.
SELECT count([processed_timestamp]) AS notnullrows,
count(*) - count([processed_timestamp]) AS nullrows
FROM table
Quanto à eficiência, isso 2x evita índice de procura / varreduras de tabela / whatever, incluindo os resultados em uma linha. Se você absolutamente requerem 2 linhas no resultado, duas passagens sobre o conjunto pode ser inevitável por causa da unioning agregados.
Espero que isso ajude
Outro método MySQL é usar a CASE
operador, que pode ser generalizado para mais alternativas do que IF()
:
SELECT CASE WHEN processed_timestamp IS NULL THEN 'NULL'
ELSE 'NOT NULL' END AS a,
COUNT(*) AS n
FROM logs
GROUP BY a
Se o seu banco de dados tem uma função COUNT eficiente (*) para uma mesa, você poderia contar o que for menor número, e subtrair.
SQL Server (começando com 2012):
SELECT IIF(ISDATE(processed_timestamp) = 0, 'NULL', 'NON NULL'), COUNT(*)
FROM MyTable
GROUP BY ISDATE(processed_timestamp);
Eu, pessoalmente, como solução de Pax, mas se você absolutamente requerem apenas uma linha retornado (como eu tive recentemente), em MS SQL Server 2005/2008 você pode "empilhar" as duas consultas usando uma 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
Espero que isso ajude
[T-SQL]:
select [case], count(*) tally
from (
select
case when [processed_timestamp] is null then 'null'
else 'not null'
end [case]
from myTable
) a
E você pode adicionar para a instrução case qualquer outra valores que você gostaria de formar uma partição, por exemplo, hoje, ontem, entre meio-dia e 02:00, depois de seis horas em uma quinta-feira.
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:. Não leu com cuidado, esta retorna uma única linha
No Oracle
SELECT COUNT(*), COUNT(TIME_STAMP_COLUMN)
FROM TABLE;
count (*) retorna a contagem de todas as linhas
count (column_name) retorna o número de linhas que não são NULL, então
SELECT COUNT(*) - COUNT(TIME_STAMP_COLUMN) NUL_COUNT,
COUNT(TIME_STAMP_COLUMN) NON_NUL_COUNT
FROM TABLE
deve fazer o trabalho.
Se a coluna é indexada, você pode acabar com algum tipo de varredura gama e evitar realmente ler a tabela.
Outra forma em 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