Tenho um banco de dados mysql onde alguma tabela usa o valor do atributo de entidade anti-padrão. Preciso consultar essa tabela e extrair atributos. Gostaria de tê-los como booleanos, ou seja, onde a junção esquerda me dá null
(para um atributo inexistente) que desejo obter false
, e se o atributo existir, desejo obter true
(ou 0 e 1).
select
-- cap.type as over_21 -- ok: some null, some "over_21"
-- coalesce(cap.type, false) as over_21 -- ok: some 0, some "over_21"
-- (case when type is not null then 1 else 0 end) as over_21 -- ok: some 0, some 1
if (cap.type, true, false) as over_21 -- wrong: all 0
-- if (cap.type is null, false, true) as over_21 -- ok again
from customer c
left join capabilities cap
on c.id = cap.user_id
and cap.type = 'over_21'
A primeira linha comentada funciona na medida em que me fornece null
o tipo de atributo, aqui "over_21". (A tabela não tem um campo de valor que eu possa usar; se o registro existir, isso significa que o atributo está definido.)
coalesce
e case
acima funcionam como esperado, mas quando uso o if
, a over_21
coluna mostra apenas 0s.
A documentação da função IF() diz:
Se expr1 for TRUE (expr1 <> 0 e expr1 IS NOT NULL), IF() retorna expr2. Caso contrário, retorna expr3.
Dado que meu expr1
é às vezes null
, pensei que isso os transformaria bem em 0s e não null
-s em 1s (ou falso e verdadeiro). Funciona com a is null
verificação explícita.
Por que não if
converte meu null
valor para booleano?
NULL não é um booleano falso, nem um inteiro 0.
Se fosse falso, então
NOT (NULL)
seria verdadeiro, certo? Mas não é:Pense em NULL como "desconhecido".
Se eu não te disser meu nome do meio, e alguém te perguntar se o nome do meio de Bill é Dave? Você diria "Não sei".
Se perguntarem se o nome do meio de Bill não é Dave? Você só pode dizer "Não sei" de novo.
Testando sua consulta:
Resultado:
Então por que o resultado foi 0 para user_id 1?
Porque em um contexto booleano, uma string não é implicitamente verdadeira. No MySQL, booleanos e inteiros são a mesma coisa, então este é realmente um contexto inteiro.
Uma string avaliada em um contexto inteiro é implicitamente convertida em um número, lendo quaisquer caracteres de dígitos iniciais e ignorando o resto. Se não houver caracteres de dígitos iniciais, então o valor numérico de uma string é 0. E 0 é falso para o MySQL.