Domanda

Ho un grande tavolo con 1 milioni di record.Purtroppo, la persona che ha creato il tavolo ha deciso di mettere le date in un varchar(50) campo.

Ho bisogno di fare un semplice confronto tra date -

datediff(dd, convert(datetime, lastUpdate, 100), getDate()) < 31

Ma non sul convert():

Conversion failed when converting datetime from character string.

A quanto pare c'è qualcosa in quel campo non piace, e dato che ci sono così tanti record, non so dire con il solo sguardo.Come posso disinfettare correttamente l'intero campo data in modo da non fallire sul convert()?Qui è quello che ho ora:

select count(*)
from MyTable
where
    isdate(lastUpdate) > 0
    and datediff(dd, convert(datetime, lastUpdate, 100), getDate()) < 31

@SQLMenace

Io non sono preoccupato per le prestazioni in questo caso.Questo sta andando essere un momento di query.Modifica della tabella in un campo di tipo datetime non è un'opzione.

@Jon Limjap

Ho provato ad aggiungere il terzo argomento, e non fa alcuna differenza.


@SQLMenace

Il problema è più probabile come i dati vengono memorizzati, ci sono solo due sicuri formati;ISO AAAAMMGG;ISO 8601 yyyy-mm-dd Thh:mm:ss:mmm (senza spazi)

Non sarebbe la isdate() controllare prendersi cura di questo?

Non ho bisogno di una precisione del 100%.Voglio solo per ottenere la maggior parte dei record degli ultimi 30 giorni.


@SQLMenace

select isdate('20080131') -- returns 1
select isdate('01312008') -- returns 0

@Brian Schkerke

Collocare il telaio e ISDATE all'interno della funzione CONVERT ().

Grazie!Che fatto.

È stato utile?

Soluzione

Posizionare il CASE e ISDATE all'interno del CONVERT() funzione.

SELECT COUNT(*) FROM MyTable
WHERE
    DATEDIFF(dd, CONVERT(DATETIME, CASE IsDate(lastUpdate)
        WHEN 1 THEN lastUpdate
        ELSE '12-30-1899'
    END), GetDate()) < 31

Sostituire '12-30-1899' con la data di default è di vostra scelta.

Altri suggerimenti

Come scrivere un cursore per scorrere il contenuto, tentando il cast per ogni voce?Quando si verifica un errore, l'uscita della chiave primaria o altri dati identificativi dell'record del problema.Non riesco a pensare a un set di base di un modo per fare questo.

Non del tutto setbased ma se solo 3 righe di 1 milione sono male ti farà risparmiare un sacco di tempo

select * into BadDates
from Yourtable
where isdate(lastUpdate) = 0

select * into GoodDates
from Yourtable
where isdate(lastUpdate) = 1

poi basta guardare la BadDates tavolo e correzione

ISDATE() sarebbe preso cura di righe che non sono stati formattati correttamente se sono state effettivamente eseguite per prime.Tuttavia, se si guarda il piano di esecuzione, probabilmente troverete che il DATEDIFF predicato viene applicato per primo - così la causa del vostro dolore.

Se si utilizza SQL Server Management Studio colpo CTRL+L per visualizzare il piano di esecuzione previsto per una determinata query.

Ricordate, SQL non è un linguaggio procedurale e corto circuito logico potrebbe funzionare, ma solo se si sta attenti a come lo si applica.

Come scrivere un cursore per scorrere il contenuto, tentando il cast per ogni voce?

Quando si verifica un errore, l'uscita della chiave primaria o altri dati identificativi dell'record del problema.

Non riesco a pensare a un set di base di un modo per fare questo.

Modifica - ah sì, mi ero dimenticato ISDATE().Sicuramente un approccio migliore rispetto all'utilizzo di un cursore.+1 per SQLMenace.

Nel convertire chiamata, è necessario specificare un terzo parametro di stile, ad esempio, il formato del datetimes che sono memorizzati come varchar, come specificato in questo documento: CAST e CONVERT (T-SQL)

Stampa il record.Dare cartacea per l'idiota che ha deciso di utilizzare un tipo di dati varchar(50) e chiedi loro di trovare il record del problema.

La prossima volta si potrebbe vedere solo il punto di scegliere un tipo di dati appropriato.

Il problema è più probabile come i dati vengono memorizzati, ci sono solo due formati di sicuro

ISO AAAAMMGG

ISO 8601 yyyy-mm-dd Thh:mm:ss:mmm(senza spazi)

queste funzionerà, non importa ciò che la vostra lingua.

Potrebbe essere necessario fare un SET DATEFORMAT AMG (o in qualunque modo i dati vengono memorizzati come) per farlo funzionare

Non isdate() controllare prendersi cura di questo?

Eseguire questo per vedere cosa succede

select isdate('20080131')
select isdate('01312008')

Sono sicuro che la modifica della tabella/colonna potrebbe non essere un'opzione a causa di precedenti requisiti di sistema, ma avete mai pensato di creare una vista che ha la data di conversione della logica, o se si sta utilizzando una versione più recente di sql, quindi si può anche utilizzare una vista indicizzata?

Vorrei suggerire di ripulire il pasticcio e cambiando la colonna datetime, perché fare cose come questa

WHERE datediff(dd, convert(datetime, lastUpdate), getDate()) < 31

non è possibile utilizzare un indice e sarà molte volte più lento se hai avuto un datetime colum,n e ha fatto

where lastUpdate > getDate() -31

È inoltre necessario prendere in considerazione le ore e i secondi di corso

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top