2008-08-26 2 views
3

У меня есть большая таблица с 1 миллионом + записей. К сожалению, человек, создавший таблицу, решил поставить даты в поле varchar(50).Ошибка преобразования даты SQL Server

Мне нужно сделать простое сравнение дат -

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

Но он не на convert():

Conversion failed when converting datetime from character string. 

Видимо есть что-то в этой области он не нравится, и так как так много записей, я не могу сказать, просто посмотрев на него. Как я могу надлежащим образом дезинфицировать все поле даты, чтобы оно не прерывалось на convert()? Вот то, что я сейчас:

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

@SQLMenace

Я не озабочен производительности в этом случае. Это будет одноразовый запрос. Изменение таблицы в поле даты и времени не является вариантом.

@Jon Limjap

Я попытался добавить третий аргумент, и это не имеет никакого значения.


@SQLMenace

Проблема, скорее всего, как хранятся данные, есть только два безопасных форматов; ISO YYYYMMDD; ISO 8601: гггг-мм-дд THH: мм: сс: ммм (без пробелов)

Не будет ли isdate() чек заботиться об этом?

У меня нет необходимости в точности 100%. Я просто хочу получить большинство записей за последние 30 дней.


@SQLMenace

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

@Brian Schkerke

Поместите СЛУЧАЙ и IsDate внутри функции CONVERT().

Спасибо! Так оно и было.

+0

Вы не указали, какие форматы датируются для поля varchar. Они последовательно отформатированы? Знание формата поможет немного решить проблему. – Kibbee 2008-08-26 14:33:10

ответ

7

Место CASE и ISDATE внутри функции CONVERT().

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

Заменить '12-30-1899' с датой по умолчанию по вашему выбору.

0

Я хотел бы предложить очистку беспорядок и изменение столбца в DateTime, потому что делать вещи, как это

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

не может использовать индекс, и это будет во много раз медленнее, чем если бы вы имели DATETIME Колум, п и сделал

where lastUpdate > getDate() -31 

Кроме того, необходимо учитывать часы и секунды, конечно

1

в вашем новообращенного вызова, необходимо указать третий paramete стиль r, например формат данных, которые хранятся в виде varchar, как указано в этом документе: CAST and CONVERT (T-SQL)

0

Распечатайте записи. Дайте печатную копию идиоту, который решил использовать varchar (50) и попросить их найти запись о проблеме.

В следующий раз они могут просто увидеть точку выбора подходящего типа данных.

0

Проблема, скорее всего, как хранятся данные, есть только два безопасные форматы

ISO ГГГГММДД

ISO 8601: гггг-мм-дд THH: мм: сс: ммм (без пробелов)

они будут работать независимо от вашего языка.

Вам может понадобиться сделать SET DATEFORMAT YMD (или что-то данные хранятся в виде), чтобы заставить его работать

1

Как о написании курсора перебрать содержимое, пытаясь бросанием для каждой записи?

При возникновении ошибки выведите первичный ключ или другие идентифицирующие данные для записи проблем.

Я не могу придумать, как это сделать.

Редактировать - да, я забыл об ISDATE(). Определенно лучший подход, чем использование курсора. +1 для SQLMenace.

0

Не будет ли проверка isdate() позаботиться об этом?

Выполнить это, чтобы увидеть, что происходит

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

Как о написании курсора перебрать содержимое, пытаясь бросанием для каждой записи? При возникновении ошибки, на выходе первичного ключа или другого определение деталей для записи проблемы. Я не могу придумать, как это сделать.

Не полностью setbased, но если только 3 строки из 1 миллиона плохо это сэкономит вам много времени

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

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

тогда просто посмотрите на таблицу BadDates и исправить

2

ISDATE() будет заботиться о строках, которые не были отформатированы правильно, если они действительно выполнялись в первую очередь. Однако, если вы посмотрите на план выполнения, вы, вероятно, обнаружите, что предикат DATEDIFF применяется сначала - вот причина вашей боли.

Если вы используете SQL Server Management Studio ударил CTRL +L для просмотра предполагаемого плана выполнения для конкретного запроса.

Помните, что SQL не является процедурным языком, и логика короткого замыкания может работать, но только если вы будете осторожны в том, как вы ее применяете.

0

Я уверен, что изменение таблицы/столбца может быть не из-за каких-либо устаревших системных требований, но вы подумали о создании представления, в котором встроена логика преобразования даты, если вы используете более новую версию sql, то вы можете даже использовать индексированный вид?

Смежные вопросы