Wie kehre ich meine Aufzeichnungen von NULL gruppiert und NOT NULL?
Frage
Ich habe eine Tabelle, die eine Spalte processed_timestamp
hat - wenn ein Datensatz dann verarbeitet wurde das Feld der Datetime enthält es verarbeitet wurde, andernfalls null
Ich möchte eine Abfrage schreiben, die zwei Zeilen zurückgibt:
NULL xx -- count of records with null timestamps
NOT NULL yy -- count of records with non-null timestamps
Ist das möglich?
Update: Der Tisch ist recht groß, so Effizienz ist wichtig. Ich konnte nur zwei Abfragen ausführen jeweils insgesamt separat zu berechnen, aber ich mag zweimal auf den Tisch schlagen, um zu vermeiden, wenn ich es vermeiden kann.
Lösung
Oracle:
Gruppe von NVL2 (Feld, 'NOT NULL', 'NULL')
Andere Tipps
In MySQL Sie etwas tun könnte, wie
SELECT
IF(ISNULL(processed_timestamp), 'NULL', 'NOT NULL') as myfield,
COUNT(*)
FROM mytable
GROUP BY myfield
In T-SQL (MS SQL Server), das funktioniert:
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
Versuchen Sie, die folgenden, es ist herstellerneutrale:
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
unseren lokalen DB2-Guru Blick auf diesem Nachdem er stimmt zu: keiner der bisher vorgestellten Lösungen (einschließlich diesem) einem vollständigen Tabellenscan vermeiden kann (der Tabelle, wenn Zeitstempel nicht indiziert ist, oder die indexotherwise). Sie alle scannen jeden Datensatz in der Tabelle genau einmal.
All CASE / IF / NVL2 () -Lösungen machen eine Null-zu-String-Konvertierung für jede Zeile, auf dem DBMS unnötige Belastung einzuführen. Diese Lösung ist nicht das Problem hat.
Wenn es Orakel dann können Sie tun:
select decode(field,NULL,'NULL','NOT NULL'), count(*)
from table
group by decode(field,NULL,'NULL','NOT NULL');
Ich bin sicher, dass andere DBs nach ähnlichem Trick ermöglichen.
Stewart,
Vielleicht diese Lösung in Betracht ziehen. Es ist (auch!) Anbieter unspezifisch.
SELECT count([processed_timestamp]) AS notnullrows,
count(*) - count([processed_timestamp]) AS nullrows
FROM table
Wie für Effizienz, dies vermeidet 2x Index sucht / Table Scans / was auch immer durch die Ergebnisse auf einer Zeile darunter. Wenn Sie unbedingt benötigen zwei Zeilen in der Folge zwei Durchgänge über den Satz kann wegen unioning Aggregate nicht zu vermeiden sein.
Hope, das hilft
Eine andere MySQL-Methode ist die CASE
Operator , die zu mehr Alternativen als IF()
verallgemeinert werden kann:
SELECT CASE WHEN processed_timestamp IS NULL THEN 'NULL'
ELSE 'NOT NULL' END AS a,
COUNT(*) AS n
FROM logs
GROUP BY a
Wenn Ihre Datenbank eine effiziente COUNT (*) Funktion für eine Tabelle hat, könnte man COUNT je nachdem, was ist die kleinere Zahl und subtrahieren.
SQL Server (ab 2012):
SELECT IIF(ISDATE(processed_timestamp) = 0, 'NULL', 'NON NULL'), COUNT(*)
FROM MyTable
GROUP BY ISDATE(processed_timestamp);
Ich persönlich mag Pax-Lösung, aber wenn Sie unbedingt benötigen nur eine Zeile zurück (wie ich vor kurzem hatte), in MS SQL Server 2005/2008 können Sie „Stapel“, die beiden Abfragen mit einem 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
Hope, das hilft
[T-SQL]:
select [case], count(*) tally
from (
select
case when [processed_timestamp] is null then 'null'
else 'not null'
end [case]
from myTable
) a
Und Sie können in die Case-Anweisung hinzufügen, was auch immer andere Werte, die Sie möchten, dass eine Partition bilden, z.B. heute, gestern, zwischen Mittag und 14.00 Uhr, nach 18.00 Uhr an einem Donnerstag.
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: nicht sorgfältig gelesen hat, gibt diese ein eine einzelne Zeile
.In Oracle
SELECT COUNT(*), COUNT(TIME_STAMP_COLUMN)
FROM TABLE;
count (*) gibt die Anzahl aller Zeilen
count (column_name) gibt die Anzahl der Zeilen, die nicht NULL sind, so
SELECT COUNT(*) - COUNT(TIME_STAMP_COLUMN) NUL_COUNT,
COUNT(TIME_STAMP_COLUMN) NON_NUL_COUNT
FROM TABLE
sollte die Arbeit tun.
Wenn die Spalte indiziert ist, können Sie mit irgendeiner Art von Bereichsscan am Ende und vermeiden tatsächlich die Tabelle zu lesen.
Eine weitere Möglichkeit, 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