Passo molto tempo a rispondere alle domande SQL su SO. Spesso mi imbatto in domande di questo 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'
vale a dire. o fare affidamento su una conversione implicita da stringa a data (errata), dei parametri specificati o affidarsi al database convertire x milioni di valori di riga del database in stringa e fare un confronto di stringhe (peggio)
Di tanto in tanto faccio un commento, soprattutto se si tratta di un utente con un alto rappresentante che scrive una risposta intelligente, ma che ritengo debba essere tipicamente meno sciatto / tipizzato con i suoi tipi di dati
Il commento di solito assume la forma che sarebbe probabilmente meglio se convertissero le stringhe in modo esplicito alle date, usando to_date (Oracle), str_to_date (MySQL), convert (SQLSERVER) o un meccanismo simile:
--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)
La mia giustificazione tecnica per farlo è che è esplicito in merito al formato della data e garantisce che i pochi parametri sorgente diventino definitivamente il tipo di dati della colonna di destinazione. Ciò impedisce qualsiasi possibilità che il database ottenga una conversione implicita errata (l'argomento 3 gennaio / 1 marzo del primo esempio) e impedisce al db di decidere di convertire un milione di valori di data nella tabella in stringhe (utilizzando una data specifica del server formattazione che potrebbe non corrispondere nemmeno al formato della data nei parametri stringa all'interno di sql) per fare il confronto - gli orrori abbondano
La mia giustificazione sociale / accademica per farlo è che SO è un sito di apprendimento; le persone su di esso acquisiscono conoscenze sia implicitamente che esplicitamente. Per colpire un principiante con questa query come risposta:
SELECT * FROM person WHERE birthdate BETWEEN '2017-01-01' AND '2017-03-01'
Potrebbe portarli a pensare che sia sensato, regolando la data per il formato che preferiscono:
SELECT * FROM person WHERE birthdate BETWEEN '01/01/2017' AND '01/03/2017'
Se hanno almeno visto un tentativo esplicito di convertire la data, potrebbero iniziare a farlo per il loro formato di data strano e uccidere alcuni bug per sempre prima che si verifichino. Dopo tutto, noi (I) cerchiamo di dissuadere le persone dall'entrare nell'abitudine di SQL injection (e qualcuno dovrebbe difendere la parametrizzazione di una query e quindi dichiarare al driver che @pBirthdate
è una stringa, quando il frontend ha un tipo datetime?)
Torna a quello che succede dopo che ho fatto la mia raccomandazione: di solito ottengo qualche pushback alla raccomandazione "essere esplicito, usa x", come "tutti gli altri lo fanno", "funziona sempre per me", "mostrami un po 'di manuale o un documento di riferimento che dice che dovrei essere esplicito "o anche" che cosa ?? "
Ho chiesto, in risposta ad alcuni di questi, se avrebbero cercato una colonna int facendo WHERE age = '99'
passando l'età come una stringa. "Non essere stupido, non abbiamo bisogno di mettere 'durante la ricerca di int" viene la risposta, quindi c'è qualche apprezzamento per diversi tipi di dati nella loro mente da qualche parte, ma forse non c'è alcuna connessione con il salto logico che la ricerca di un int colonna passando una stringa (apparentemente sciocca) e cercando una colonna data passando una stringa (apparentemente sensibile) è ipocrisia
Quindi nelle nostre SQL abbiamo un modo di scrivere le cose come numeri (usa numeri, senza delimitatori), cose come stringhe di stringhe (usa qualsiasi cosa tra i delimitatori degli apostrofi). Perché non esistono delimitatori per le date? È un tipo di dati così fondamentale nella maggior parte dei DB? Questa cosa potrebbe forse essere risolta semplicemente avendo un modo di scrivere una data nello stesso modo in cui javascript ci consente di specificare un'espressione regolare mettendo /
su entrambi i lati di alcuni caratteri. %codice%. Perché non avere qualcosa per le date?
In realtà, per quanto ne so, (solo) Microsoft Access in realtà ha simboli che indicano "una data è stata scritta tra questi delimitatori" così possiamo ottenere una buona scorciatoia come /Hello\s+world/
ma la presentazione della data è ancora suscettibile di dare problemi per esempio mm / di vs dd / mm, perché MS ha sempre giocato veloce e libero con le cose che la folla di VB pensava fosse una buona idea
Ritorno al punto principale: sto sostenendo che è saggio essere espliciti con questo mezzo che ci obbliga a passare una moltitudine di diversi tipi di dati come stringhe ..
È un'affermazione valida?
Devo continuare questa crociata? È un punto valido che la tipizzazione a caratteri stringati sia un no-no moderno? O tutti i RDBMS (incluse le versioni antiche) là fuori, quando si spinge una query WHERE datecolumn = #somedate#
, sicuramente convertono la stringa in una data e fanno la ricerca senza convertire i dati della tabella / perdere l'uso degli indici? Sospetto di no, almeno per esperienza personale di Oracle 9. Sospetto anche che possano esserci alcuni scenari di allontanamento con essa se le stringhe sono sempre scritte in qualche formato standard ISO, e la colonna ha un certo sapore di data, quindi la il parametro stringa sarà sempre convertito in modo implicito corretto. Questo è giusto?
È un compito utile?
Molte persone non sembrano averlo capito, o se ne importano, o mostrano qualche ipocrisia in quanto sono i loro intatti ma le loro date sono stringhe .. Comune a molti però è che poche persone si sono mai voltate e hanno detto "sai cosa, sono d'accordo con il tuo punto, sarò esplicito sulle mie date d'ora in poi".