Comment retourner mes enregistrements groupés par NULL et NOT NULL?

J’ai une table qui a une colonne processing_timestamp – si un enregistrement a été traité, alors ce champ contient la date / heure à laquelle il a été traité, sinon il est nul.

Je veux écrire une requête qui renvoie 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: La table est assez grande, donc l’efficacité est importante. Je pourrais juste lancer deux requêtes pour calculer chaque total séparément, mais je veux éviter de bash la table deux fois si je peux l’éviter.

Oracle:

group by nvl2 (champ, ‘NOT NULL’, ‘NULL’)

En MySQL, vous pourriez faire quelque chose comme

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

En 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, c’est neutre pour les fournisseurs:

 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 regardé notre gourou DB2 local, il est d’accord: aucune des solutions présentées à ce jour (y compris celle-ci) ne peut éviter une parsing de table complète (de la table si timestamp n’est pas indexé). Ils parsingnt tous chaque enregistrement de la table exactement une fois.

Toutes les solutions CASE / IF / NVL2 () effectuent une conversion null-to-ssortingng 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 les autres bases de données autorisent un tour similaire.

Stewart,

Peut-être envisager cette solution. C’est (aussi!) Un fournisseur non spécifique.

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

En ce qui concerne l’efficacité, cela évite les recherches par index 2x / parsings 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 au-dessus de l’ensemble peuvent être inévitables en raison de l’union des agrégats.

J’espère que cela t’aides

Une autre méthode MySQL consiste à utiliser l’ opérateur CASE , qui peut être généralisé à plus 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 

Si votre firebase database a une fonction COUNT (*) efficace pour une table, vous pouvez calculer le nombre le plus petit et soustraire.

SQL Server (à partir de 2012):

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

Personnellement, j’aime la solution de Pax, mais si vous ne devez absolument renvoyer qu’une seule ligne (comme je l’ai récemment fait), dans MS SQL Server 2005/2008, vous pouvez “emstackr” les deux requêtes à l’aide d’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 

J’espère que cela t’aides

[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 append dans la déclaration de cas quelles que soient les autres valeurs que vous souhaitez créer une partition, par exemple aujourd’hui, hier, entre midi et 14h, après 18h un jeudi.

 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 renvoie une seule ligne.

Dans Oracle

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

count (*) 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’parsing de plage et éviter de lire la table.

Une autre façon 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