2009-08-07 27 views
5

¿Cómo comparar la igualdad de valor en SQL con nulo?¿Cómo hacer la comparación de igualdad en SQL con un comportamiento similar al de C#?

Para aquellos familiarizados con C#, aquí están los resultados de la comparación de los valores anulables:

null == null : true 
null == john : false 
null == paul : false 
john == null : false 
john == john : true 
john == paul : false 
paul == null : false 
paul == john : false 
paul == paul : true 

La solución más fácil que he encontrado en SQL es a unido en los campos con valores nulos en algún valor centinela (por ejemplo, 'scoobydoo') a continuación, compararlos

coalesce(A, 'scoobydoo') = coalesce(B, 'scoobydoo') 

Pero eso es normal kludge si alguien utiliza el valor centinela, si a pasa a ser nulo y B es 'scoobydoo', entonces la expresión anterior produciría cierto

Esto es exactamente mi propósito en pedir la lógica del código anterior (desencadenador UPDATE T-SQL):

-- detect if the value changes 

if (select invoice_date from inserted) <> 
    (select invoice_date from deleted) begin 

    -- do something to summary tables here 

end 

cómo hacer comparación de igualdad en SQL con C# -como comportamiento?

[EDIT: Se encuentra la respuesta here]

probaron el código (buen apoyo booleano Postgres, FTW!):

select 

    A, B, 

    A = B, 
    A IS NOT DISTINCT FROM B, -- "logically" same as above 

    A <> B, 
    A IS DISTINCT FROM B -- "logically" same as above 

from( 
    values 
    (null, null), 
    (null, 'john'), 
    (null, 'paul'), 
    ('john', null), 
    ('john', 'john'), 
    ('john', 'paul'), 
    ('paul', null), 
    ('paul', 'john'), 
    ('paul', 'paul')) as x(A,B) 

[EDIT: Probado código de Jon, su respuesta en el tipo de igualdad de semi -trabajo (acaba de tratar el nulo como falsa de todos modos), pero su respuesta en bombas de desigualdad fuera]

Probado el código (Postgres buen apoyo booleano, FTW!):

select 

    A, B, 

    A = B, 
    A IS NOT DISTINCT FROM B, -- "logically" same as above 
    coalesce((A = B) or (A is null and B is null), false), 
    -- tested Jon's code for ==, semi-work, coalesced to make it true/false only 


    A <> B, 
    A IS DISTINCT FROM B, -- "logically" same as above 
    (A <> B) and (A is not null or B is not null) 
    -- tested Jon's code for !=, bombs out 

from( 
    values 
    (null, null), 
    (null, 'john'), 
    (null, 'paul'), 
    ('john', null), 
    ('john', 'john'), 
    ('john', 'paul'), 
    ('paul', null), 
    ('paul', 'john'), 
    ('paul', 'paul')) as x(A,B) 

[EDIT: registró otro question relacionados con éste]

[EDIT: se publicaron los resultados basados ​​en la investigación de Jon en la semántica que no trabajan para la comparación desigualdad]

select 

    A, B, 

    A = B, 
    A IS NOT DISTINCT FROM B, -- "logically" same as above 
    (A = B) or (A is null and B is null), 
    -- tested Jon's code for == 


    A <> B, 
    A IS DISTINCT FROM B -- "logically" same as above, 
    (A <> B) and (A is not null or B is not null) 
    -- tested Jon's code for !=, bombs out 

from( 
    values 
    (null, null), 
    (null, 'john'), 
    (null, 'paul'), 
    ('john', null), 
    ('john', 'john'), 
    ('john', 'paul'), 
    ('paul', null), 
    ('paul', 'john'), 
    ('paul', 'paul')) as x(A,B) 


    a | b | ?column? | ?column? | ?column? | ?column? | ?column? | ?column? 
------+------+----------+----------+----------+----------+----------+---------- 
null | null | null  | t  | t  | null  | f  | f 
null | john | null  | f  | null  | null  | t  | null 
null | paul | null  | f  | null  | null  | t  | null 
john | null | null  | f  | null  | null  | t  | null 
john | john | t  | t  | t  | f  | f  | f 
john | paul | f  | f  | f  | t  | t  | t 
paul | null | null  | f  | null  | null  | t  | null 
paul | john | f  | f  | f  | t  | t  | t 
paul | paul | t  | t  | t  | f  | f  | f 
(9 rows) 

la semántica no laborables para la desigualdad que me impulsó a publicar otro question :-)

[EDIT: Probado nueva respuesta de Jon]

select 

    A, B, 

    A = B as e, 
    A IS NOT DISTINCT FROM B AS e_works, -- "logically" same as above 
    (A = B) or (A is null and B is null) AS e_semi_work, -- tested Jon's code for ==, works if we treat null as false 


    A <> B as ie, 
    A IS DISTINCT FROM B as ie_works, -- "logically" same as above, 
    (A <> B) and (A is not null or B is not null) as ie_not_work, -- tested Jon's code for !=, bombs out 

    (A <> B) or ((A is null or B is null) and (A is not null or B is not null)) as ie_semi_works, -- this works(well it is, if you treat null as false), 

    not ((A = B) or (A is null and B is null)) as ie_not_work2 -- this doesn't work 


from( 
    values 
    (null, null), 
    (null, 'john'), 
    (null, 'paul'), 
    ('john', null), 
    ('john', 'john'), 
    ('john', 'paul'), 
    ('paul', null), 
    ('paul', 'john'), 
    ('paul', 'paul')) as x(A,B) 

Resultados:

a | b | e | e_works | e_semi_work | ie | ie_works | ie_not_work | ie_semi_works | ie_not_work2 
------+------+------+---------+-------------+------+----------+-------------+---------------+-------------- 
null | null | null | t  | t   | null | f  | f   | null   | f 
null | john | null | f  | null  | null | t  | null  | t    | null 
null | paul | null | f  | null  | null | t  | null  | t    | null 
john | null | null | f  | null  | null | t  | null  | t    | null 
john | john | t | t  | t   | f | f  | f   | f    | f 
john | paul | f | f  | f   | t | t  | t   | t    | t 
paul | null | null | f  | null  | null | t  | null  | t    | null 
paul | john | f | f  | f   | t | t  | t   | t    | t 
paul | paul | t | t  | t   | f | f  | f   | f    | f 
(9 rows) 
+0

s/eliminar/eliminar/en la última muestra. ¿Da los valores iniciales para Paul & John explícitamente? –

+1

Dup de http://stackoverflow.com/questions/680824/sql-equality-inequality-comparison-with-nullable-values ​​ –

+0

Si se trata de T-SQL, ¿es definitivamente un duplicado de una pregunta de Postgres? ¿Funcionará la misma respuesta? –

Respuesta

5

Editar nuevo ... coalescencia el resultado debería funcionar y hace las cosas un poco más simple:

Igualdad:

where COALESCE((A = B) or (A is null and B is null), false) 

Estoy de acuerdo que no es terriblemente agradable .

EDITAR: Vilx señaló un problema con A <> B.Creo que esto funcionará sin embargo:

where (A <> B) or ((A is null or B is null) and 
        (A is not null or B is not null)) 

Puede ser más fácil de hacer esto sin embargo:

where !(COALESCE((A = B) or (A is null and B is null)), false) 
+0

+1 para proporcionar el bajo -la semántica del capó de IS DISTINCT FROM – Hao

+1

Umm ... perdónenme si estoy equivocado, pero ¿no fallaría el segundo si A fuera NULL y B no lo fuera? –

+0

@Vilx: ¿De qué te preocupa? 'A <> B' será verdadero, y' (A no es nulo o B no es nulo) 'será verdadero porque B no es nulo, por lo que el resultado general es verdadero, como se desee. –

3

Si se trata de Microsoft SQL Server, entonces usted está buscando la opción ANSI_NULLS. Si se trata de otro DBMS, deberá leer la documentación correspondiente. Algunos de ellos no son compatibles con esto en absoluto.

Agregado: Oh, noté que mencionas T-SQL. Es es MSSQL entonces! :)

+0

Me gusta ! Sé que no es el * estándar *, ¡pero maldita sea! Gracias. – Kieron

+1

En teoría, también podría ser Sybase. –

+0

Umm, OK, no lo sabía. :) –

Cuestiones relacionadas