Domanda

Ho una tabella che ha una colonna elaborated_timestamp - se un record è stato elaborato, quel campo contiene il datetime che è stato elaborato, altrimenti è nullo.

Voglio scrivere una query che restituisca due righe:

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

È possibile?

Aggiornamento: la tabella è abbastanza grande, quindi l'efficienza è importante. Potrei semplicemente eseguire due query per calcolare ogni totale separatamente, ma voglio evitare di colpire la tabella due volte se posso evitarlo.

È stato utile?

Soluzione

Oracle:

raggruppa per nvl2 (campo, 'NOT NULL', 'NULL')

Altri suggerimenti

In MySQL potresti fare qualcosa del genere

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

In T-SQL (MS SQL Server), funziona:

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

Prova quanto segue, è indipendente dal fornitore:

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

Dopo aver dato un'occhiata al nostro guru DB2 locale, concorda: nessuna delle soluzioni presentate finora (inclusa questa) può evitare una scansione completa della tabella (della tabella se il timestamp non è indicizzato, o dell'indice in altro modo). Scansionano tutti i record nella tabella esattamente una volta.

Tutte le soluzioni CASE / IF / NVL2 () eseguono una conversione da null a stringa per ogni riga, introducendo un carico non necessario sul DBMS. Questa soluzione non presenta questo problema.

Se è un oracolo, allora puoi fare:

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

Sono sicuro che altri DB consentano un trucco simile.

Stewart,

Forse considera questa soluzione. È (anche!) Fornitore non specifico.

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

Per quanto riguarda l'efficienza, questo evita ricerche di indice 2x / scansioni di tabelle / qualunque cosa includendo i risultati su una riga. Se hai assolutamente bisogno di 2 righe nel risultato, due passaggi sul set potrebbero essere inevitabili a causa degli aggregati di unione.

Spero che questo aiuti

Un altro metodo MySQL è utilizzare Operatore CASE , che può essere generalizzato a più alternative rispetto a 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 il tuo database ha un'efficace funzione COUNT (*) per una tabella, puoi COUNT qualunque sia il numero più piccolo e sottrarre.

SQL Server (a partire dal 2012):

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

Personalmente mi piace la soluzione di Pax, ma se hai assolutamente bisogno di restituire solo una riga (come avevo fatto di recente), in MS SQL Server 2005/2008 puoi " stack " le due query che utilizzano un 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

Spero che questo aiuti

[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 puoi aggiungere nell'istruzione case qualsiasi altro valore desideri formare una partizione, ad es. oggi, ieri, tra mezzogiorno e le 14:00, dopo le 18:00 di giovedì.

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

Modifica: non letto attentamente, questo restituisce una singola riga.

In Oracle

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

count (*) restituisce il conteggio di tutte le righe

count (nome_colonna) restituisce il numero di righe che non sono NULL, quindi

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

dovrebbe fare il lavoro.

Se la colonna è indicizzata, potresti finire con una sorta di scansione dell'intervallo ed evitare di leggere effettivamente la tabella.

Un altro modo 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 
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top