Ich verbringe viel Zeit damit, SQL-Fragen zu SO zu beantworten. Ich stoße häufig auf Fragen dieser Art:
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'
dh entweder auf eine implizite Konvertierung der angegebenen Parameter von Zeichenfolge zu Datum (schlecht) oder auf die Datenbank, die x Millionen Datenbankzeilenwerte in Zeichenfolge konvertiert und einen Zeichenfolgenvergleich durchführt (schlechter)
Ich mache gelegentlich einen Kommentar, besonders wenn es sich um einen High-Rep-Benutzer handelt, der eine kluge Antwort schreibt, der jedoch meiner Meinung nach mit seinen Datentypen weniger schlampig / streng getippt sein sollte
Der Kommentar hat normalerweise die Form, dass es wahrscheinlich besser wäre, wenn sie ihre Zeichenfolgen explizit mit to_date (Oracle), str_to_date (MySQL), convert (SQLSERVER) oder einem ähnlichen Mechanismus in Datumsangaben konvertieren:
--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)
Meine technische Rechtfertigung dafür ist, dass das Format des Datums explizit angegeben wird und sichergestellt ist, dass die wenigen Quellparameter definitiv zum Datentyp der Zielspalte werden. Dies verhindert, dass die Datenbank implizit eine falsche Konvertierung erhält (das Argument vom 3. Januar / 1. März des allerersten Beispiels), und verhindert, dass die Datenbank beschließt, eine Million Datumswerte in der Tabelle in Zeichenfolgen zu konvertieren (wobei ein serverspezifisches Datum verwendet wird) Formatierungen, die möglicherweise nicht einmal mit dem Format des Datums in den Zeichenfolgenparametern innerhalb von sql) übereinstimmen, um den Vergleich durchzuführen - Horror gibt es zuhauf
Meine soziale / akademische Rechtfertigung dafür ist, dass SO eine Lernseite ist; Personen, die sich damit befassen, erwerben implizit oder explizit Wissen. So treffen Sie einen Neuling mit dieser Abfrage als Antwort:
SELECT * FROM person WHERE birthdate BETWEEN '2017-01-01' AND '2017-03-01'
Könnte sie dazu bringen, dies für sinnvoll zu halten und das Datum für ein von ihnen bevorzugtes Format anzupassen:
SELECT * FROM person WHERE birthdate BETWEEN '01/01/2017' AND '01/03/2017'
Wenn sie zumindest einen expliziten Versuch gesehen haben, das Datum zu konvertieren, könnten sie damit beginnen, es für ihr seltsames Datumsformat zu tun und einige Ewige-Fehler zu beseitigen, bevor sie auftauchen. Schließlich versuchen wir (ich), die Leute davon abzuhalten, in die Gewohnheit der SQL-Injection einzusteigen (und würde jemand befürworten, eine Abfrage zu parametrisieren und dann dem Treiber zu deklarieren, dass @pBirthdate
es sich um eine Zeichenfolge handelt, wenn das Frontend einen Datetime-Typ hat?).
Zurück zu dem, was passiert, nachdem ich meine Empfehlung abgegeben habe: Normalerweise erhalte ich einen Pushback zu der Empfehlung "explizit sein, x verwenden", wie "jeder tut es", "es funktioniert immer für mich", "zeige mir ein Handbuch oder ein Referenzdokument das sagt, ich sollte explizit "oder sogar" was? "
Als Antwort auf einige dieser Fragen habe ich gefragt, ob sie eine int-Spalte durchsuchen würden, indem WHERE age = '99'
sie das Alter als Zeichenfolge übergeben. "Seien Sie nicht albern, wir müssen nicht 'setzen, wenn Sie nach int suchen", lautet die Antwort. Daher haben sie irgendwo eine gewisse Wertschätzung für verschiedene Datentypen, aber vielleicht auch keine Verbindung zu dem logischen Sprung, der beim Suchen eines int besteht Spalte durch Übergeben einer Zeichenfolge (scheinbar albern) und Durchsuchen einer Datumsspalte durch Übergeben einer Zeichenfolge (scheinbar sinnvoll) ist Heuchelei
Also haben wir in unseren SQLs eine Möglichkeit, Dinge als Zahlen zu schreiben (verwenden Sie Zahlen ohne Begrenzer), Dinge als Zeichenketten (verwenden Sie irgendetwas zwischen Apostroph-Begrenzern). Warum keine Begrenzer für Datumsangaben? Es ist so ein grundlegender Datentyp in den meisten DB? Könnte diese ganze Sache vielleicht einfach dadurch gelöst werden, dass man ein Datum auf die gleiche Weise schreibt, wie Javascript es uns ermöglicht, einen regulären Ausdruck zu spezifizieren, indem man /
beide Seiten einiger Zeichen einsetzt. /Hello\s+world/
. Warum nicht etwas für Dates haben?
Meines Wissens verfügt Microsoft Access (nur) tatsächlich über Symbole, die angeben, dass "ein Datum zwischen diesen Begrenzern geschrieben wurde", sodass wir eine gute Abkürzung erhalten, WHERE datecolumn = #somedate#
aber die Datumsdarstellung kann weiterhin Probleme verursachen, z. B. mm / di vs dd / mm, weil MS immer schnell und locker mit dem Zeug gespielt haben, fand das VB-Publikum eine gute Idee
Zurück zum Hauptpunkt: Ich behaupte, es ist ratsam, mit diesem Medium explizit umzugehen, das uns zwingt, eine Vielzahl verschiedener Datentypen als Zeichenfolgen zu übergeben.
Ist es eine gültige Behauptung?
Soll ich diesen Kreuzzug fortsetzen? Ist es ein gültiger Punkt, dass das strikte Tippen ein modernes Nein-Nein ist? Oder werden alle RDBMSs (einschließlich alter Versionen) da draußen, wenn eine Abfrage durchgeführt WHERE datecolumn = 'string value'
wird, die Zeichenfolge absolut sicher korrekt in ein Datum konvertieren und die Suche durchführen, ohne Tabellendaten zu konvertieren / die Verwendung von Indizes zu verlieren? Ich vermute nein, zumindest aus persönlicher Erfahrung mit Oracle 9. Ich vermute auch, dass es einige Ausweichszenarien geben kann, wenn Zeichenfolgen immer in einem ISO-Standardformat geschrieben werden und die Spalte eine Datumsangabe enthält string parameter werden implizit immer korrekt konvertiert. Macht das alles richtig?
Lohnt es sich?
Viele Leute scheinen es nicht zu verstehen, oder es ist ihnen egal, oder sie zeigen eine Heuchelei, weil ihre Ints Ints sind, aber ihre Daten Zeichenketten Ich stimme Ihrem Punkt zu. Ich werde meine Daten von nun an explizit nennen. "
WHERE age = '0x0F'
eine Datenbank nach 15-Jährigen sucht.
WHERE datecolumn =
01/02 / 12'` hat, wenn er möglicherweise nach dem Jahr 1912, 2012, 2001, 1901, 12 oder 1 fragt. Es ist auch ein Problem außerhalb der Datenbankwelt, der Nummer von Programmierern, die nicht verstehen können, warum das Konvertieren"09"
in ein int einen Absturz verursacht, sind Legion, 9 ist keine gültige Oktalziffer und eine führende 0 macht den String in vielen Systemen oktal