Question

J'ai une table qui a une colonne timbre traité - si un enregistrement a été traité, ce champ contient l'heure à laquelle il a été traité, sinon il est nul.

Je souhaite é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: Le tableau étant assez volumineux, l'efficacité est essentielle. Je pourrais juste lancer deux requêtes pour calculer chaque total séparément, mais je veux éviter de toucher deux fois à la table si je peux l'éviter.

Était-ce utile?

La solution

Oracle:

groupe par nvl2 (champ, 'NOT NULL', 'NULL')

Autres conseils

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 consulté 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, en introduisant une charge inutile sur le SGBD. Cette solution n’a pas ce problème.

Si c'est un oracle, 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 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 recherches d'index / analyses de table / quoi que ce soit 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 vous aidera

Une autre méthode MySQL consiste à utiliser la CASE , qui peut être généralisé à plus de variantes 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 base de données dispose d'une fonction COUNT (*) efficace pour une table, vous pouvez COUNT le plus petit nombre 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 bien la solution de Pax, mais si vous ne devez absolument renvoyer qu'une seule ligne (comme je l'avais récemment), vous pouvez "empiler" dans MS SQL Server 2005/2008. les deux requêtes 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 vous aidera

[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 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.

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

Modifier: n'a pas lu attentivement, celui-ci renvoie une seule ligne.

Sous Oracle

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

count (*) renvoie le décompte 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 
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top