2008-08-26 16 views
3

Ich habe eine große Tabelle mit 1 Million + Datensätze. Leider hat die Person, die die Tabelle erstellt hat, beschlossen, Daten in ein Feld varchar(50) zu legen.SQL Server DateTime Konvertierung Fehler

Ich brauche einen einfachen Datumsvergleich zu tun -

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

Aber es scheitert an den convert():

Conversion failed when converting datetime from character string. 

Offenbar ist es etwas in diesem Bereich ist es nicht mögen, und da sind so viele Aufzeichnungen, ich kann es nicht nur sagen, indem ich es ansehe. Wie kann ich das gesamte Datumsfeld ordnungsgemäß bereinigen, damit es nicht auf der convert() fehlschlägt? Hier ist, was ich habe jetzt:

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

@SQLMenace

Ich bin nicht besorgt über die Leistung in diesem Fall. Dies wird eine einmalige Abfrage sein. Das Ändern der Tabelle in ein Datetime-Feld ist keine Option.

@Jon Limjap

Ich habe versucht, das dritte Argument hinzufügen, und es macht keinen Unterschied.


@SQLMenace

Das Problem ist höchstwahrscheinlich, wie die Daten gespeichert sind, gibt es nur zwei sichere Formate; ISO JJJJMMTT; ISO 8601 yyyy-mm-dd Thh: mm: ss: mmm (ohne Leerzeichen)

Wäre nicht das isdate() Check darum kümmern?

Ich brauche keine 100% ige Genauigkeit. Ich möchte nur die meisten Aufzeichnungen der letzten 30 Tage bekommen.


@SQLMenace

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

@Brian Schkerke

Platz der Fall ist und im Inneren des ISDATE CONVERT() Funktion.

Vielen Dank! Das hat es getan.

+0

Sie haben nicht erwähnt, für welche Formate die Datumsangaben im varchar-Feld stehen. Sind sie konsistent formatiert? Wenn man das Format kennt, hilft das bei der Lösung des Problems. – Kibbee

Antwort

7

Platzieren Sie die CASE und ISDATE innerhalb der CONVERT() Funktion.

SELECT COUNT(*) FROM MyTable WHERE DATEDIFF(dd, CONVERT(DATETIME, CASE IsDate(lastUpdate) when 1 then lastUpdate ELSE '12-30-1899' end), getDate()) < 31

Ersetzen '12-30-1899' mit dem Standarddatum Ihrer Wahl.

0

Ich würde vorschlagen, das Chaos und die Änderung der Spalte in eine Datetime-Reinigung, weil Sachen zu tun wie dieses

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

können keinen Index verwenden, und es wird oft langsamer sein, als wenn Sie ein Datetime-Colum hatte, n und tat

where lastUpdate > getDate() -31 

Sie müssen auch berücksichtigen, Stunden und Sekunden natürlich

1

In Ihrem convert Anruf, benötigen Sie einen dritten Art paramete angeben B. das Format der Datumsangaben, die als varchar gespeichert sind, wie in diesem Dokument angegeben: CAST and CONVERT (T-SQL)

0

Die Datensätze ausdrucken. Gib dem Idioten, der sich entschieden hat, einen Varchar (50) zu verwenden, den Ausdruck und frage ihn, ob er den Problemdatensatz finden kann.

Das nächste Mal sehen sie vielleicht gerade den Punkt der Wahl eines geeigneten Datentyps.

0

Das Problem ist höchstwahrscheinlich, wie die Daten gespeichert werden, gibt es nur zwei sichere Formate

ISO YYYYMMDD

ISO 8601 yyyy-mm-dd Thh: mm: ss: mmm (ohne Leerzeichen)

diese funktionieren, egal was Ihre Sprache ist.

Möglicherweise müssen Sie eine SET DATEFORMAT YMD tun (oder was auch immer die Daten gespeichert, wie) es

machen arbeiten, um einen Cursor auf Schleife durch den Inhalt, für jeden Eintrag
1

Wie über das Schreiben die Besetzung versucht?

Wenn ein Fehler auftritt, geben Sie den Primärschlüssel oder andere identifizierende Details für den Problemdatensatz aus.

Ich kann nicht denken, eine Set-basierte Möglichkeit, dies zu tun.

Bearbeiten - ah ja, ich habe ISDATE vergessen(). Definitiv ein besserer Ansatz als die Verwendung eines Cursors. +1 zu SQLMenace.

0

Würde nicht die isdate() Kontrolle darauf achten?

Run, das zu sehen, was

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

geschieht Wie wäre es, einen Cursor in einer Schleife durch den Inhalt zu schreiben, die Besetzung für jeden Eintrag versucht? Wenn ein Fehler auftritt, Ausgabe der Primärschlüssel oder andere Identifizieren von Details für den Problemsatz. Ich kann nicht auf eine Set-basierte Art und Weise denken, dies zu tun.

Nicht ganz setbased aber wenn nur drei Reihen von 1 Million schlecht sind, wird es Ihnen viel Zeit

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

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

dann schauen Sie in dem BadDates Tisch und beheben, dass

2

Die sparen ISDATE() würde sich um die Zeilen kümmern, die nicht richtig formatiert wurden, wenn sie tatsächlich zuerst ausgeführt würden. Wenn Sie sich jedoch den Ausführungsplan ansehen, werden Sie wahrscheinlich feststellen, dass das DATEDIFF-Prädikat zuerst angewendet wird - also die Ursache Ihres Schmerzes.

Wenn Sie mit SQL Server Management Studio getroffen CTRL +L den geschätzten Ausführungsplan für eine bestimmte Abfrage anzuzeigen.

Denken Sie daran, SQL ist keine prozedurale Sprache und Kurzschlusslogik kann funktionieren, aber nur, wenn Sie vorsichtig sind, wie Sie es anwenden.

0

Ich bin sicher, dass die Änderung der Tabelle/Spalte möglicherweise keine Option aufgrund von Altsystemanforderungen ist, aber haben Sie darüber nachgedacht, eine Ansicht zu erstellen, die die Datumkonvertierungslogik eingebaut hat, wenn Sie eine neuere Version verwenden von sql, dann kannst du vielleicht sogar eine indizierte Sicht verwenden?