2012-04-20 24 views
16

estoy trabajando en una consulta que es bastante similar al siguiente:¿La manera más fácil de eliminar valores NULL en SELECT DISTINCT?

CREATE TABLE #test (a char(1), b char(1)) 

INSERT INTO #test(a,b) VALUES 
('A',NULL), 
('A','B'), 
('B',NULL), 
('B',NULL) 

SELECT DISTINCT a,b FROM #test 

DROP TABLE #test 

El resultado es, como era de esperar,

a b 
------- 
A NULL 
A B 
B NULL 

La salida me gustaría ver en la actualidad es:

a b 
------- 
A B 
B NULL 

Es decir, si una columna tiene un valor en algunos registros pero no en otros, quiero arrojar la fila con NULL para esa columna. Sin embargo, si una columna tiene un valor NULL para todos los registros, deseo conservar ese NULL.

¿Cuál es la forma más simple/más elegante de hacer esto en una sola consulta?

Tengo la sensación de que esto sería simple si no estuviera agotado el viernes por la tarde.

+0

Puede un valor de la columna 'a' tener más de un valor no nulo en 'B'? Si ese es el caso, ¿espera obtener ambos valores? –

+0

Lo siento, acabo de volver a esto hoy. Para todos los registros del grupo, cada columna está: 100% poblada con un valor único, 100% NULL o parcialmente poblada con un valor único y parcialmente NULL. Por ejemplo: (1, 2, NULO), (1, 2, NULO), (1, NULO, NULO) deben reducirse a (1, 2, NULO). –

Respuesta

8

Prueba esto:

select distinct * from test 
where b is not null or a in (
    select a from test 
    group by a 
    having max(b) is null) 

, usted puede obtener el violín here.

Nota si usted sólo puede tener un valor no nulo en b, esto se puede simplificar a:

select a, max(b) from test 
group by a 
+1

+1 muy succint –

+0

El segundo hace lo que necesito en este caso. Cada columna es enteramente NULA, completamente poblada con un solo valor, o parcialmente poblada con un solo valor y parcialmente NULL. MAX() resuelve el problema elegantemente. Gracias. –

0
SELECT DISTINCT t.a, t.b 
FROM #test t 
WHERE b IS NOT NULL 
OR  NOT EXISTS (SELECT 1 FROM #test u WHERE t.a = u.a AND u.b IS NOT NULL) 
ORDER BY t.a, t.b 
0

Este es un requisito muy raro. Me pregunto cómo lo necesitas.

SELECT DISTINCT a, b 
FROM test t 
WHERE NOT (b IS NULL 
      AND EXISTS 
       (SELECT * 
       FROM test ta 
       WHERE ta.a = t.a 
        AND ta.b IS NOT NULL 
       ) 
      ) 
    AND NOT (a IS NULL 
      AND EXISTS 
       (SELECT * 
       FROM test tb 
       WHERE tb.b = t.b 
        AND tb.a IS NOT NULL 
       ) 
      ) 
0

Bueno, me gusta especialmente esta solución, pero parece el más adecuado para mí .Tenga en cuenta que su descripción de lo que quiere suena exactamente como lo que se obtiene con un LEFT JOIN, por lo que:

SELECT DISTINCT a.a, b.b 
FROM #test a 
    LEFT JOIN #test b ON a.a = b.a 
     AND b.b IS NOT NULL 
1

Prueba esto:

create table test(
x char(1), 
y char(1) 
); 

insert into test(x,y) values 
('a',null), 
('a','b'), 
('b', null), 
('b', null) 

Consulta:

with has_all_y_null as 
(
    select x 
    from test 
    group by x 
    having sum(case when y is null then 1 end) = count(x) 
) 
select distinct x,y from test 
where 

    (
     -- if a column has a value in some records but not in others, 
     x not in (select x from has_all_y_null) 

     -- I want to throw out the row with NULL 
     and y is not null 
    ) 
    or 
    -- However, if a column has a NULL value for all records, 
    -- I want to preserve that NULL 
    (x in (select x from has_all_y_null)) 

order by x,y 

Salida:

X Y 
A B 
B NULL 

Prueba en vivo: http://sqlfiddle.com/#!3/259d6/16

EDITAR

Al ver Mosty's answer, he simplificado mi código:

with has_all_y_null as 
(
    select x 
    from test 
    group by x 

    -- having sum(case when y is null then 1 end) = count(x) 
    -- should have thought of this instead of the code above. Mosty's logic is good: 
    having max(y) is null 
) 
select distinct x,y from test 
where 
    y is not null 
    or 
    (x in (select x from has_all_y_null)) 
order by x,y 

Yo prefiero enfoque CTE, que tiene una lógica más autodocumentado :-)

Puede también ponga la documentación en un enfoque que no sea CTE, si es consciente de ello:

select distinct * from test 
where b is not null or a in 
    (-- has all b null 
    select a from test 
    group by a 
    having max(b) is null) 
0
SELECT a,b FROM #test t where b is not null 
union 
SELECT a,b FROM #test t where b is null 
and not exists(select 1 from #test where a=t.a and b is not null) 

Resultado:

a b 
---- ---- 
A B 
B NULL 
1
;WITH CTE 
    AS 
    (
    SELECT DISTINCT * FROM #test 
    ) 
    SELECT a,b 
    FROM CTE   
    ORDER BY CASE WHEN b IS NULL THEN 9999 ELSE b END ; 
+0

¿Podría agregar una breve descripción de cómo funciona su solución? –

Cuestiones relacionadas