Passo molto tempo a rispondere alle domande SQL su SO. Mi capita spesso di incontrare domande di questo genere:
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'
ovvero fare affidamento su una conversione implicita da stringa a data (non valida), dei parametri dati o fare affidamento sul database che converte x milioni di valori di riga del database in stringa e che esegue un confronto di stringhe (peggio)
Occasionalmente faccio un commento, in particolare se si tratta di un utente di alto livello che scrive una risposta intelligente, ma che ritengo debba essere meno sciatto / tipizzato con stringhe con i loro tipi di dati
Il commento di solito prende la forma che probabilmente sarebbe meglio se convertissero esplicitamente le loro stringhe in 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)
Le mie giustificazioni tecniche per farlo è che è esplicito sul formato della data e garantisce che i pochi parametri di origine diventino sicuramente 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 conoscenza implicitamente o esplicitamente. Per colpire un principiante con questa query come risposta:
SELECT * FROM person WHERE birthdate BETWEEN '2017-01-01' AND '2017-03-01'
Potrebbe indurli a pensare che sia sensato, modificando la data per il formato che preferiscono:
SELECT * FROM person WHERE birthdate BETWEEN '01/01/2017' AND '01/03/2017'
Se almeno vedessero un tentativo esplicito di convertire la data, potrebbero iniziare a farlo per il loro strano formato di data e uccidere alcuni bug per sempre prima che insorgano. Dopotutto, noi (I) proviamo a dissuadere le persone dall'entrare nell'abitudine di iniezione SQL (e qualcuno vorrebbe sostenere la parametrizzazione di una query e quindi dichiarare al driver che @pBirthdate
è una stringa, quando il frontend ha un tipo di data-ora?)
Tornando a ciò che succede dopo che ho formulato la mia raccomandazione: di solito ricevo un po 'di pushback alla raccomandazione "sii esplicito, usa x", come "lo fanno tutti gli altri", "funziona sempre per me", "mostrami un manuale o un documento di riferimento che dice che dovrei essere esplicito "o addirittura" cosa ?? "
Ho chiesto, in risposta ad alcuni di questi, se avrebbero cercato una colonna int facendo WHERE age = '99'
passare l'età come stringa. "Non essere sciocco, non abbiamo bisogno di mettere 'durante la ricerca di int", arriva la risposta, quindi c'è qualche apprezzamento per i diversi tipi di dati nella loro mente da qualche parte, ma forse proprio nessuna connessione al salto logico che la ricerca di un int colonna passando una stringa (apparentemente sciocca) e cercare una colonna data passando una stringa (apparentemente sensibile) è ipocrisia
Quindi nei nostri SQL abbiamo un modo per scrivere cose come numeri (usare numeri, senza delimitatori), cose come stringhe di stringhe (usare qualcosa tra delimitatori di apostrofi) .. Perché nessun delimitatore per le date? È un tipo di dati così fondamentale nella maggior parte dei DB? Tutto questo potrebbe forse essere risolto semplicemente avendo un modo di scrivere una data nello stesso modo in cui JavaScript ci consente di specificare una regex inserendo /
entrambi i lati di alcuni caratteri. /Hello\s+world/
. Perché non avere qualcosa per le date?
In realtà, per quanto ne so, (solo) Microsoft Access in realtà ha simboli che indicano "è stata scritta una data tra questi delimitatori" in modo da poter ottenere una buona scorciatoia come WHERE datecolumn = #somedate#
ma la presentazione della data è ancora suscettibile di dare problemi, ad esempio mm / di vs dd / mm, perché la SM ha sempre giocato in maniera veloce e libera con le cose che la folla di VB pensava fosse una buona idea
Torna al punto principale: sto sostenendo che è saggio essere espliciti con questo mezzo che ci costringe a passare una moltitudine di tipi di dati diversi come stringhe.
È un'affermazione valida?
Devo continuare questa crociata? È un punto valido che digitare in modo rigoroso sia un no-no moderno? O tutti i RDBMS (comprese le versioni antiche) là fuori, quando una query verrà WHERE datecolumn = 'string value'
sicuramente sicuramente convertita correttamente la stringa in una data e farà 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 potrebbero esserci alcuni scenari di fuga se le stringhe sono sempre scritte in un formato standard ISO e la colonna ha un sapore di data, quindi il il parametro string verrà sempre convertito implicitamente correttamente. Questo lo rende giusto?
È un compito utile?
Molte persone non sembrano ottenerlo, o non gliene importa, o mostrano ipocrisia in quanto i loro ints sono ints ma le loro date sono stringhe .. Comune per la maggior parte 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 ".
WHERE age = '0x0F'
è un modo valido per sperare che un database cerchi quindicenni.
WHERE datecolumn =
01/02/12 '' dove è possibile che stiano chiedendo per l'anno 1912, 2012, 2001, 1901, 12 o 1. È anche un problema al di fuori del mondo del database, il numero dei programmatori che non riescono a capire perché la conversione"09"
in un int causi un arresto anomalo sono legioni, 9 non è una cifra ottale valida e uno 0 iniziale rende la stringa ottale in molti sistemi