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.

Foi útil?

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 
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top