Come posso restituire i miei record raggruppati per NULL e NOT NULL?
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.
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