2009-05-12 19 views
5

estoy usando SQL Server 2005. Con la consulta a continuación (simplificado de mi consulta real):conde valor nulo distinto y es eliminado por un agregado

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 

¿Hay alguna manera de hacer un recuento distinta sin obteniendo

"Advertencia: el valor nulo es eliminado por un agregado u otra operación SET".

Estas son las alternativas que se me ocurren:

  1. ANSI_WARNINGS Desactivación de
  2. La separación en dos consultas, una con recuento diferente y una cláusula where para eliminar los nulos, uno con la suma:

    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. ignorar la advertencia en el cliente

¿Hay una mejor manera de hacerlo? Probablemente iré por la ruta 2, pero no me gusta la duplicación del código.

+0

Creo que su código anterior está bien, la base de datos no debería molestarlo con sorpresas, por eso es una advertencia, porque algunos programadores pueden pensar que DISTINCT debería incluir el conteo de nulos de todos modos. Creo que la alerta de advertencia cumple con ANSI SQL. –

+0

Tu explicación tiene sentido. Aún así, no me gustan las advertencias si puedo evitarlas. –

Respuesta

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 

Gracias a Eoin trabajé encontrar una manera de hacer esto. Puede contar distintos valores, incluidos los nulos, y luego eliminar el recuento debido a nulos si hubiera alguno usando una suma distinta.

2

cualquier lugar que tenga un valor nulo devuelto posiblemente, utilizar

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

Eso será sub a cabo todos sus valores nulos de -1 para la duración de la consulta y serán contados/agregados como tal, entonces Sólo puede hacer a la inversa de la consulta envoltura fina ...

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

Quería evitar la división en dos consultas y la combinación. Sin embargo, gracias a tu idea de que ya lo resolví, publicaré una respuesta. –

+0

¡No me gusta esta idea para nada! ¿Qué pasa si los datos llegan tarde? O 'desconocido' es un estado perfectamente válido? –

+0

Estoy diseñando específicamente para un caso en el que no deseo incluir valores NULL en el recuento. –

1

Si no te gusta la duplicación de código, ¿por qué no utilizar una expresión de tabla común? p.ej.

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

Esa es una buena idea en la que no había pensado. Pero la duplicación de código que realmente no me gustó fue el grupo by y join, del cual no se puede deshacer así. Gracias sin embargo. –

2

Esta es una nota tardía, pero como fue la devolución en Google, quise mencionarla.

Cambiar NULL a otro valor es una mala idea (tm).

COUNT() lo está haciendo, no DISTINTO.

En su lugar, use DISTINCT en una subconsulta y devuelve un número, y agregue eso en la consulta externa.

Un ejemplo sencillo de esto es:

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

Esto permite COUNT(*) para ser utilizado, que no ignora NULL (porque cuenta registros, no los valores).

Cuestiones relacionadas