J'ai une table qui a une colonne processed_timestamp
- si un enregistrement a été traité, ce champ contient la date et l'heure auxquelles il a été traité, sinon il est null.
Je veux écrire une requête qui retourne deux lignes:
NULL xx -- count of records with null timestamps
NOT NULL yy -- count of records with non-null timestamps
Est-ce possible?
Mise à jour: Le tableau est assez grand, l'efficacité est donc importante. Je pourrais juste exécuter deux requêtes pour calculer chaque total séparément, mais je veux éviter de toucher la table deux fois si je peux l'éviter.
Oracle:
grouper par nvl2 (champ, 'NOT NULL', 'NULL')
Dans MySQL, vous pouvez faire quelque chose comme
SELECT
IF(ISNULL(processed_timestamp), 'NULL', 'NOT NULL') as myfield,
COUNT(*)
FROM mytable
GROUP BY myfield
Dans T-SQL (MS SQL Server), cela fonctionne:
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
Essayez ce qui suit, il est indépendant du vendeur:
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
Après avoir examiné cette question auprès de notre gourou local DB2, il est d’accord: aucune des solutions présentées à ce jour (y compris celle-ci) ne peut éviter une analyse complète de la table (de la table si l’horodatage n’est pas indexé, ou de l’index sinon). Ils parcourent tous les enregistrements de la table exactement une fois.
Toutes les solutions CASE/IF/NVL2 () effectuent une conversion de chaîne nulle pour chaque ligne, introduisant une charge inutile sur le SGBD. Cette solution n'a pas ce problème.
Si c'est Oracle alors vous pouvez faire:
select decode(field,NULL,'NULL','NOT NULL'), count(*)
from table
group by decode(field,NULL,'NULL','NOT NULL');
Je suis sûr que d'autres bases de données permettent une astuce similaire.
Stewart,
Peut-être envisager cette solution. C'est (aussi!) Un vendeur non spécifique.
SELECT count([processed_timestamp]) AS notnullrows,
count(*) - count([processed_timestamp]) AS nullrows
FROM table
Pour ce qui est de l'efficacité, cela évite les recherches d'index 2x/les analyses de table/peu importe en incluant les résultats sur une ligne. Si vous avez absolument besoin de 2 lignes dans le résultat, deux passages sur l'ensemble peuvent être inévitables en raison de l'union des agrégats.
J'espère que cela t'aides
Si votre base de données dispose d'une fonction COUNT (*) efficace pour une table, vous pouvez COUNT le nombre le plus faible et soustrayez-la.
Une autre méthode MySQL consiste à utiliser l'opérateur CASE
, qui peut être généralisé à davantage d'alternatives 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
SQL Server (à partir de 2012):
SELECT IIF(ISDATE(processed_timestamp) = 0, 'NULL', 'NON NULL'), COUNT(*)
FROM MyTable
GROUP BY ISDATE(processed_timestamp);
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'a pas lu attentivement, celui-ci ne renvoie qu'une seule ligne.
[T-SQL]:
select [case], count(*) tally
from (
select
case when [processed_timestamp] is null then 'null'
else 'not null'
end [case]
from myTable
) a
Et vous pouvez ajouter à l'instruction case n'importe quelles autres valeurs pour lesquelles vous souhaitez former une partition, par exemple. aujourd'hui, hier, entre midi et 14h, après 18h le jeudi.
Dans Oracle
SELECT COUNT(*), COUNT(TIME_STAMP_COLUMN)
FROM TABLE;
nombre (*) renvoie le nombre de toutes les lignes
count (nom_colonne) renvoie le nombre de lignes qui ne sont pas NULL, donc
SELECT COUNT(*) - COUNT(TIME_STAMP_COLUMN) NUL_COUNT,
COUNT(TIME_STAMP_COLUMN) NON_NUL_COUNT
FROM TABLE
devrait faire le travail.
Si la colonne est indexée, vous pouvez vous retrouver avec une sorte d'analyse de plage et éviter de lire le tableau.
Une autre manière de 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
Personnellement, j'aime bien la solution de Pax, mais si vous n'avez absolument besoin que d'une seule ligne retournée (comme je l'avais récemment), vous pouvez "empiler" les deux requêtes à l'aide d'un CTE sous MS SQL Server 2005/2008.
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
J'espère que cela t'aides