Gambiarra para comparar inteiros quando o SQL não responde

Essa dúvida apareceu em outro lugar e estou postando aqui a solução.

O problema

Ao fazer um where coluna > 100000 o banco de dados estava retornando todos os valores. Mesmo alterando o tipo da coluna para numérico o resultado era sempre o mesmo.

A gambiarra

Alterar a função para where 1*coluna > 1*100000 para forçar o sistema a compreender o uso de valores numéricos.

Explicação e poréns

Isso funciona porque a maior parte das linguagens de programação trabalha da esquerda para direita, e portanto ao encontrar um “número” seguido de “uma operação numérica” ele vai forçar o outro lado da operação a ser numérico também.

Ao fazer “number * text” a linguagem vai tentar interpretar isso como “number * number”.

Primeiro porém, não vai funcionar sempre, não é elegante e não é eficiente. Isso deve ser usado como último recurso e não como estrategia.

Segundo porém, não funciona ao contrário, tem que colocar o “1” antes do elemento que está dando problemas.

Acho que é isso o resumo da gambiarra.

Qual sistema de banco de dados você está utilizando? A conversão implícita de tipos (implicit casting) que acontece no WHERE pode ser implementada de maneira diferente em sistemas de bancos de dados diferentes. Exemplo: crie uma tabela com uma coluna de texto, adicione textos que podem ser convertidos para inteiros e tente fazer a consulta WHERE coluna > N, onde N é inteiro (valor sem aspas).

Exemplo no SQLite

Converte implicitamente os valores da tabela para inteiro, dado que o valor na condição WHERE é inteiro:

sqlite> CREATE TABLE test (f1 TEXT);
sqlite> INSERT INTO test VALUES ('10'), ('20'), ('30');
sqlite> SELECT * FROM test WHERE f1 > 15;
20
30

Exemplo no PostgreSQL

O PostgreSQL se recusa a executar a consulta caso os tipos não sejam os mesmos:

rows=# CREATE TABLE test (f1 TEXT);
CREATE TABLE
rows=# INSERT INTO test VALUES ('10'), ('20'), ('30');
INSERT 0 3
rows=# SELECT * FROM test WHERE f1 > 15;
ERROR:  operator does not exist: text > integer
LINE 1: SELECT * FROM test WHERE f1 > 15;
                                    ^
HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.

É uma boa prática fazer a conversão explícita, pois dessa forma os erros não passam despercebidos (sugiro ver a palestra WAT do Gary Bernhardt para ver os efeitos bizarros disso). O casting explícito pode ser feito de duas formas, como no exemplo abaixo (o nome do banco de dados é rows):

rows=# SELECT * FROM test WHERE f1::INTEGER > 15;
 f1 
----
 20
 30
(2 rows)
rows=# SELECT * FROM test WHERE CAST(f1 AS INTEGER) > 15;
 f1 
----
 20
 30
(2 rows)

Você também poderia converter o valor da coluna para inteiro e então não precisaria do casting explícito:

rows=# ALTER TABLE test ALTER COLUMN f1 TYPE INTEGER USING f1::INTEGER;
ALTER TABLE
rows=# SELECT * FROM test WHERE f1 > 15;
 f1 
----
 20
 30
(2 rows)
1 Curtida