2009-05-12 5 views
5

J'utilise SQL Server 2005. Avec la requête ci-dessous (simplifiée de ma requête réelle):Nombre valeur distincte et nul est éliminé par un agrégat

select a,count(distinct b),sum(a) from 
(select 1 a,1 b union all 
select 2,2 union all 
select 2,null union all 
select 3,3 union all 
select 3,null union all 
select 3,null) a 
group by a 

Est-il possible de faire un compte distinct sans "

" Avertissement: La valeur nulle est éliminée par un agrégat ou une autre opération SET. "

Voici les alternatives que je peux penser:

  1. Turning ANSI_WARNINGS hors
  2. La séparation en deux requêtes, l'un avec compte distinct et une clause where pour éliminer les valeurs nulles, l'une avec la somme:

    select t1.a, t1.countdistinctb, t2.suma from 
    (
        select a,count(distinct b) countdistinctb from 
        (
         select 1 a,1 b union all 
         select 2,2 union all 
         select 2,null union all 
         select 3,3 union all 
         select 3,null union all 
         select 3,null 
        ) a 
        where a.b is not null 
        group by a 
    ) t1 
    left join 
    (
        select a,sum(a) suma from 
        (
         select 1 a,1 b union all 
         select 2,2 union all 
         select 2,null union all 
         select 3,3 union all 
         select 3,null union all 
         select 3,null 
        ) a 
        group by a 
    ) t2 on t1.a=t2.a 
    
  3. ignorer l'avertissement dans le client

Y a-t-il une meilleure façon de faire cela? Je vais probablement descendre la route 2, mais n'aime pas la duplication du code.

+0

Je pense que votre ancien code est très bien, la base de données ne devrait pas vous déranger avec des surprises, c'est pourquoi il déclenche un avertissement, car certains programmeurs pourraient penser que DISTINCT devrait inclure le comptage des NULL. Je pense que cette alerte est conforme à ANSI SQL. –

+0

Votre explication a du sens. Pourtant, je n'aime pas les avertissements si je peux les éviter. –

Répondre

5
select a,count(distinct isnull(b,-1))-sum(distinct case when b is null then 1 else 0 end),sum(a) from 
    (select 1 a,1 b union all 
    select 2,2 union all 
    select 2,null union all 
    select 3,3 union all 
    select 3,null union all 
    select 3,null) a 
    group by a 

Merci à Eoin j'ai travaillé une façon de le faire. Vous pouvez compter les valeurs distinctes, y compris les valeurs NULL, puis supprimer le nombre dû aux valeurs nulles s'il y en a qui utilisent une somme distincte.

2

partout où vous avez un nul peut-être retourné, utilisez

CASE WHEN Column IS NULL THEN -1 ELSE Column END AS Column 

Cela va sous toutes vos valeurs NULL pour -1 pour la durée de la requête et ils seront comptés/agrégés en tant que tel, vous peut simplement faire l'inverse dans votre requête d'emballage fin ...

SELECT 
    CASE WHEN t1.a = -1 THEN NULL ELSE t1.a END as a 
    , t1.countdistinctb 
    , t2.suma 
+0

Je voulais éviter la scission en deux requêtes et la combinaison. Merci à votre idée, je l'ai bien compris, je vais poster une réponse. –

+0

N'aime pas cette idée du tout! Et si les données arrivent en retard? Ou 'inconnu' est un état parfaitement valide? –

+0

Je conçois spécifiquement pour un cas où je ne veux pas inclure des valeurs NULL dans le compte. –

1

Si vous n'aimez pas la duplication de code, pourquoi ne pas utiliser une expression de table commune? par exemple.

WITH x(a, b) AS 
     (
       select 1 a,1 b union all 
       select 2,2 union all 
       select 2,null union all 
       select 3,3 union all 
       select 3,null union all 
       select 3,null 
     ) 
select t1.a, t1.countdistinctb, t2.suma from 
(
     select a,count(distinct b) countdistinctb from 
     x a 
     where a.b is not null 
     group by a 
) t1 
left join 
(
     select a,sum(a) suma from 
     x a 
     group by a 
) t2 on t1.a=t2.a 
+0

C'est une bonne idée à laquelle je n'avais pas pensé. Mais la duplication de code que je n'aimais vraiment pas était le groupe par et joint, ce qui ne peut pas être éliminé comme ça. Merci quand même. –

2

Ceci est une note tardive, mais étant donné que c'était le retour sur Google, je voulais le mentionner.

La modification de NULL à une autre valeur est une mauvaise idée (tm).

COUNT() le fait, pas DISTINCT. Au lieu de cela, utilisez DISTINCT dans une sous-requête et qui renvoie un nombre et l'agréger dans la requête externe.

Un exemple simple de ceci est:

WITH A(A) AS (SELECT NULL UNION ALL SELECT NULL UNION ALL SELECT 1) 
SELECT COUNT(*) FROM (SELECT DISTINCT A FROM A) B; 

Cela permet COUNT(*) à utiliser, qui ne néglige pas les valeurs NULL (car il compte les enregistrements, et non des valeurs).

Questions connexes