Comment puis-je retourner mes enregistrements regroupés par NULL et non NULL?

J'ai une table qui a une colonne processed_timestamp - si un enregistrement a été traité, ce champ contient la date et l'heure à laquelle il a été traité, sinon il est null.

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?

Update: la table est assez grande, donc l'efficacité est importante. Je pourrais simplement exécuter deux requêtes pour calculer chaque total séparément, mais je veux éviter de frapper la table deux fois si je peux l'éviter.

47
demandé sur paxdiablo 2008-10-27 13:48:48

14 réponses

Oracle:

Grouper par nvl2(field, 'NOT NULL','NULL')

22
répondu trunkc 2008-10-27 10:56:10

Dans MySQL, vous pouvez faire quelque chose comme

SELECT 
    IF(ISNULL(processed_timestamp), 'NULL', 'NOT NULL') as myfield, 
    COUNT(*) 
FROM mytable 
GROUP BY myfield
43
répondu Stefan Gehrig 2008-10-27 10:53:03

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
33
répondu Tomalak 2008-10-27 11:02:54

Essayez ce qui suit, c'est neutre pour le fournisseur:

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 vu notre gourou DB2 local, 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 scannent tous les enregistrements de la table exactement une fois.

Toutes les solutions CASE / IF / NVL2 () effectuent une conversion null-to-string pour chaque ligne, introduisant une charge inutile sur le SGBD. Cette solution n'a pas que problème.

20
répondu paxdiablo 2009-12-29 07:58:34

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 DB permettent une astuce similaire.

5
répondu ADEpt 2008-10-27 10:53:51

Stewart,

Peut-être envisager cette solution. C'est (aussi!) 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 2x index seeks/table scans/whatever en incluant les résultats sur une ligne. Si vous avez absolument besoin de 2 lignes dans le résultat, deux passes sur l'ensemble peuvent être inévitables en raison de l'union des agrégats.

J'espère que cela aide

5
répondu James Green 2008-10-27 13:20:12

Une autre méthode MySQL consiste à utiliser CASE Opérateur , 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
1
répondu Tom 2008-10-27 11:03:07

Si votre base de données a une fonction COUNT (*) efficace pour une table, vous pouvez compter le nombre le plus petit et soustraire.

1
répondu dkretz 2008-10-28 02:49:34

SQL Server (à partir de 2012):

SELECT IIF(ISDATE(processed_timestamp) = 0, 'NULL', 'NON NULL'), COUNT(*)
FROM MyTable
GROUP BY ISDATE(processed_timestamp);
1
répondu Jatin Sanghvi 2016-02-23 12:14:38

J'aime personnellement la solution de Pax, mais si vous n'avez absolument besoin que d'une seule ligne retournée (comme je l'avais récemment), dans MS SQL Server 2005/2008 vous pouvez "empiler" les deux requêtes en utilisant 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 aide

0
répondu James Green 2008-10-27 11:05:48

[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 dans l'instruction case toutes les autres valeurs que vous souhaitez former une partition, par exemple aujourd'hui, hier, entre midi et 14h00, après 18h00 un jeudi.

0
répondu Unsliced 2008-10-27 12:36:27
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.

0
répondu Aleksey Otrubennikov 2008-10-27 14:04:30

Dans Oracle

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

Count (*) renvoie le nombre de toutes les lignes

Count (column_name) 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 pourriez vous retrouver avec une sorte d'analyse de plage et éviter de lire réellement la table.

0
répondu EvilTeach 2008-10-28 02:54:13

Une autre façon dans 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 
0
répondu Refael 2016-03-03 05:46:35