Je passe beaucoup de temps à répondre aux questions SQL sur SO. Je rencontre fréquemment des requêtes de cet acabit:
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'
c'est-à-dire soit en s'appuyant sur une conversion implicite de chaîne en date (mauvaise), des paramètres donnés, soit en se basant sur la base de données convertissant x millions de valeurs de ligne de base de données en chaîne et effectuant une comparaison de chaîne (pire)
Je fais parfois un commentaire, en particulier si c'est un utilisateur de haut niveau qui écrit une réponse intelligente, mais que je pense vraiment devrait être moins bâclé / tapé avec leurs types de données
Le commentaire prend généralement la forme qu'il serait probablement préférable de convertir explicitement leurs chaînes en dates, en utilisant to_date (Oracle), str_to_date (MySQL), convert (SQLSERVER) ou un mécanisme similaire:
--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)
Ma justification technique pour ce faire est qu'elle est explicite quant au format de la date et garantit que les quelques paramètres source deviennent définitivement le type de données de la colonne cible. Cela empêche toute possibilité que la base de données obtienne une conversion implicite incorrecte (l'argument du 3 janvier / 1er mars du tout premier exemple) et empêche la base de données de décider de convertir un million de valeurs de date dans la table en chaînes (en utilisant une date spécifique au serveur formatage qui pourrait même ne pas correspondre au format de la date dans les paramètres de chaîne dans le sql) afin de faire la comparaison - les horreurs abondent
Ma justification sociale / académique pour le faire est que SO est un site d'apprentissage; les gens y acquièrent des connaissances implicitement ou explicitement. Pour frapper un débutant avec cette requête comme réponse:
SELECT * FROM person WHERE birthdate BETWEEN '2017-01-01' AND '2017-03-01'
Cela pourrait les amener à penser que cela est raisonnable, en ajustant la date pour un format qu'ils préfèrent:
SELECT * FROM person WHERE birthdate BETWEEN '01/01/2017' AND '01/03/2017'
S'ils ont au moins vu une tentative explicite de convertir la date, ils pourraient commencer à le faire pour leur format de date étrange, et tuer des bugs pour toujours avant qu'ils ne surviennent. Après tout, nous (j') essayons de dissuader les gens de prendre l'habitude d'injection SQL (et est-ce que quelqu'un préconiserait de paramétrer une requête puis de déclarer au pilote qu'il @pBirthdate
s'agit d'une chaîne, lorsque le frontend a un type datetime?)
Revenons à ce qui se passe après avoir fait ma recommandation: j'obtiens généralement une réponse à la recommandation "soyez explicite, utilisez x", comme "tout le monde le fait", "ça marche toujours pour moi", "montrez-moi un manuel ou un document de référence qui dit que je devrais être explicite "ou même" quoi ?? "
J'ai demandé, en réponse à certains d'entre eux, s'ils rechercheraient une colonne int en faisant WHERE age = '99'
passer l'âge comme une chaîne. "Ne sois pas stupide, nous n'avons pas besoin de mettre" lors de la recherche int "vient la réponse, donc il y a une certaine appréciation pour différents types de données dans leur esprit quelque part, mais peut-être juste aucun lien avec le saut logique que la recherche d'un int colonne en passant une chaîne (apparemment idiot) et la recherche d'une colonne de date en passant une chaîne (apparemment sensible) est de l'hypocrisie
Donc, dans nos SQL, nous avons un moyen d'écrire des choses sous forme de nombres (utilisez des chiffres, sans délimiteurs), des choses sous forme de chaînes de caractères (utilisez n'importe quoi entre les délimiteurs d'apostrophe). Pourquoi pas de délimiteurs pour les dates? C'est un type de données fondamental dans la plupart des bases de données? Est-ce que tout cela pourrait être résolu simplement en ayant un moyen d'écrire une date de la même manière que javascript nous permet de spécifier une expression régulière en mettant de /
chaque côté de certains caractères. /Hello\s+world/
. Pourquoi ne pas avoir quelque chose pour les dates?
En fait, à ma connaissance, (uniquement) Microsoft Access a en fait des symboles qui indiquent "une date a été écrite entre ces délimiteurs" afin que nous puissions obtenir un bon raccourci comme WHERE datecolumn = #somedate#
mais la présentation de la date est toujours susceptible de poser des problèmes, par exemple mm / di vs dd / mm, parce que les MS ont toujours joué vite et avec les trucs que la foule VB pensait être une bonne idée
Revenons au point principal: je soutiens qu'il est sage d'être explicite avec ce médium qui nous oblige à passer une multitude de types de données différents sous forme de chaînes.
Est-ce une affirmation valable?
Dois-je continuer cette croisade? Est-ce un point valable que la saisie en chaîne est un non-non moderne? Ou est-ce que tous les SGBDR (y compris les versions anciennes) là-bas, lorsque poussé une requête, WHERE datecolumn = 'string value'
convertiront certainement correctement la chaîne en une date et effectueront la recherche sans convertir les données de table / perdre l'utilisation des index? Je soupçonne que non, du moins par expérience personnelle d'Oracle 9. Je soupçonne également qu'il peut y avoir des scénarios d'évasion si les chaînes sont toujours écrites dans un certain format standard ISO, et la colonne est une saveur de date, puis le Le paramètre de chaîne sera toujours correctement implicitement converti. Est-ce que cela le rend juste?
Est-ce une tâche valable?
Beaucoup de gens ne semblent pas comprendre, ou s'en moquent, ou présentent une certaine hypocrisie dans la mesure où leurs ints sont des ints mais leurs dates sont des chaînes. quoi, je suis d'accord avec votre point. Je serai explicite sur mes dates à partir de maintenant ".
WHERE age = '0x0F'
c'est un moyen valable d'espérer qu'une base de données recherchera des jeunes de quinze ans.
WHERE datecolumn =
01/02/12 '' où il est possible qu'ils demandent l'année 1912, 2012, 2001, 1901, 12 ou 1. C'est aussi un problème en dehors du monde de la base de données, le nombre des programmeurs qui ne comprennent pas pourquoi la conversion"09"
en int entraîne un crash sont légion, 9 n'est pas un chiffre octal valide et un 0 de tête rend la chaîne octale dans de nombreux systèmes