Passo muito tempo respondendo perguntas sobre SQL no SO. Costumo encontrar perguntas deste tipo:
SELECT * FROM person WHERE birthdate BETWEEN '01/01/2017' AND '01/03/2017'
SELECT * FROM person WHERE birthdate BETWEEN '2017-01-01' AND '2017-03-01'
SELECT * FROM person WHERE birthdate BETWEEN 'some string' AND 'other string'
ou seja, baseando-se em uma conversão implícita de string para data (inválida), dos parâmetros fornecidos ou no banco de dados convertendo x milhões de valores de linha de banco de dados em string e fazendo uma comparação de strings (pior)
Ocasionalmente, faço um comentário, especialmente se é um usuário de alta reputação que escreve uma resposta inteligente, mas que, na minha opinião, realmente deveria estar sendo menos desleixado / digitado com seus tipos de dados
O comentário geralmente assume a forma de que provavelmente seria melhor se eles convertessem explicitamente suas strings em datas, usando to_date (Oracle), str_to_date (MySQL), convert (SQLSERVER) ou algum mecanismo semelhante:
--oracle
SELECT * FROM person WHERE birthdate BETWEEN TO_DATE('20170101', 'YYYYMMDD') AND TO_DATE('20170301', 'YYYYMMDD')
--mysql
SELECT * FROM person WHERE birthdate BETWEEN STR_TO_DATE('20170101', '%Y%m%d') AND STR_TO_DATE('20170301', '%Y%m%d')
--SQLS, ugh; magic numbers
SELECT * FROM person WHERE birthdate BETWEEN CONVERT(datetime, '20170101', 112) AND CONVERT(datetime, '20170301', 112)
Minhas justificativas técnicas para fazer isso são explícitas quanto ao formato da data e garantem que os poucos parâmetros de origem se tornem definitivamente o tipo de dados da coluna de destino. Isso evita qualquer possibilidade de o banco de dados ter uma conversão implícita incorreta (o argumento de 3 de janeiro / 1º de março do primeiro exemplo) e impede que o banco de dados decida converter um milhão de valores de data na tabela em seqüências de caracteres (usando alguma data específica do servidor formatação que pode nem coincidir com o formato da data nos parâmetros da string no sql) para fazer a comparação - os horrores são abundantes
Minha justificativa social / acadêmica para fazer isso é que o SO é um site de aprendizado; as pessoas nele adquirem conhecimento de forma implícita ou explícita. Para acertar um novato com esta consulta como resposta:
SELECT * FROM person WHERE birthdate BETWEEN '2017-01-01' AND '2017-03-01'
Pode levá-los a pensar que isso é sensato, ajustando a data para algum formato que preferirem:
SELECT * FROM person WHERE birthdate BETWEEN '01/01/2017' AND '01/03/2017'
Se eles pelo menos viram alguma tentativa explícita de converter a data, eles podem começar a fazê-lo em seu formato estranho de data e matar alguns bugs eternos antes que surjam. Afinal, nós (I) tentamos dissuadir as pessoas de adotar o hábito de injeção de SQL (e alguém defenderia parametrizar uma consulta e depois declarar para o driver que @pBirthdate
é uma string, quando o frontend tem um tipo de data e hora?)
Voltando ao que acontece depois que eu faço minha recomendação: geralmente recebo alguma resposta à recomendação "seja explícito, use x", como "todo mundo faz isso", "sempre funciona para mim", "me mostre algum documento de referência ou manual que diz que eu deveria ser explícito "ou mesmo" o que? "
Perguntei, em resposta a alguns deles, se eles pesquisariam uma coluna int WHERE age = '99'
passando a idade como uma string. "Não seja bobo, não precisamos colocar 'ao pesquisar int", vem a resposta; portanto, há alguma apreciação por diferentes tipos de dados em sua mente em algum lugar, mas talvez apenas nenhuma conexão com o salto lógico que procura um int coluna passando uma string (aparentemente boba) e pesquisando uma coluna de data passando uma string (aparentemente sensata) é hipocrisia
Assim, em nossos SQLs, temos uma maneira de escrever coisas como números (use numéricos, sem delimitadores), coisas como cadeias de caracteres (use qualquer coisa entre delimitadores de apóstrofo) .. Por que não há delimitadores para datas? É um tipo de dados tão fundamental na maioria dos bancos de dados? Talvez tudo isso possa ser resolvido apenas com uma maneira de escrever uma data da mesma maneira que o javascript nos permite especificar uma regex colocando os /
dois lados de alguns caracteres. /Hello\s+world/
. Por que não ter algo para datas?
Na verdade, que eu saiba, (apenas) o Microsoft Access realmente possui símbolos que indicam "uma data foi escrita entre esses delimitadores" para que possamos obter um bom atalho como, WHERE datecolumn = #somedate#
mas a apresentação da data ainda pode causar problemas, por exemplo, mm / di vs dd / mm, porque o MS sempre tocou rápido e solto com as coisas que o público da VB achou que era uma boa ideia
Voltando ao ponto principal: estou argumentando que é sensato ser explícito com esse meio que nos força a passar uma infinidade de tipos de dados diferentes como strings.
É uma afirmação válida?
Devo continuar esta cruzada? É um ponto válido que a digitação estrita é um não-não moderno? Ou todos os RDBMSs (incluindo versões antigas) lá fora, quando lançados uma consulta, WHERE datecolumn = 'string value'
certamente convertem corretamente a string em uma data e fazem a pesquisa sem converter dados da tabela / perder o uso de índices? Suspeito que não, pelo menos com a experiência pessoal do Oracle 9. Suspeito também que possa haver alguns cenários de fuga com isso, se as strings sempre forem escritas em algum formato padrão ISO e a coluna tiver algum sabor de data, então o O parâmetro string sempre será convertido corretamente implicitamente. Isso faz certo?
É uma tarefa que vale a pena?
Muitas pessoas parecem não entender, ou não se importam, ou exibem alguma hipocrisia, porque suas ints são ints, mas suas datas são seqüências de caracteres. Comum, no entanto, é que poucas pessoas já se viraram e disseram "você sabe concordo com o seu ponto. Serei explícito sobre minhas datas a partir de agora ".
WHERE age = '0x0F'
é uma forma válida para esperar um banco de dados irá procurar por jovens de quinze anos ..
WHERE datecolumn =
01/02/12 '', onde é possível que eles estejam pedindo o ano de 1912, 2012, 2001, 1901, 12 ou 1. Também é um problema fora do mundo do banco de dados, o número de programadores que não conseguem entender por que a conversão"09"
para um int está causando um acidente são legião, 9 não é um dígito octal válido e um 0 faz com que o octal corda em um monte de sistemas