2011-01-25 2 views
1

У меня есть промежуточная область, в которой я пытаюсь проверить данные, проходя через множество итераций проверки. В настоящее время я борюсь с некоторыми проблемами с столбцом nvarchar (50), который я пытаюсь преобразовать в дату.Ошибка преобразования даты TSQL - моя неспособность понять набор результатов

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

SELECT * 
    FROM (SELECT * FROM STAGE_TABLE WHERE ISDATE(DATE_COL) = 1) 
WHERE CAST(DATE_COL AS DATE) < GETDATE() 

... это приводит к стандарту «Конверсия не удалась при преобразовании даты и/или времени из символьной строки».

Но вот здесь вещи становятся странными для меня. Если изменить вышеуказанное заявление на следующее:

SELECT CAST(DATE_COL AS DATE) 
    FROM (SELECT * FROM STAGE_TABLE WHERE ISDATE(DATE_COL) = 1) 

... все хорошо, и все, что я сделал перемещаются бросок из ИНЕК выбора пункта. Я думаю, что я упускаю что-то на фундаментальном уровне.

FWIW, если бы я должен был вытащить все записи из STAGE_TABLE без предложения WHERE ISDATE, у меня были бы плохо сформированные строки даты.

Любые идеи очень ценятся!

ответ

3

Вы должны обнаружить, что первый запрос объединяет два предложения WHERE в один и разрабатывает CAST перед ISDATE (сбой).

2-й запрос явно обработать WHERE первого, так CAST никогда не видит плохие данные

Я просто проверял, и может подтвердить:

create table STAGE_TABLE (date_col nvarchar(50)) 
insert into STAGE_TABLE select 'a' 
insert into STAGE_TABLE select '20100101' 

Первый запрос

SELECT * 
    FROM (SELECT * FROM STAGE_TABLE WHERE ISDATE(DATE_COL) = 1) X 
WHERE CAST(DATE_COL AS DATE) < GETDATE() 

Первый план

|--Filter(WHERE:(isdate([tempdb].[dbo].[STAGE_TABLE].[date_col])=(1))) 
     |--Table Scan(OBJECT:([tempdb].[dbo].[STAGE_TABLE]), WHERE:(CONVERT(date,[tempdb].[dbo].[STAGE_TABLE].[date_col],0)<getdate())) 

Второй запрос

SELECT CAST(DATE_COL AS DATE) 
    FROM (SELECT * FROM STAGE_TABLE WHERE ISDATE(DATE_COL) = 1) X 

Второй план

|--Compute Scalar(DEFINE:([Expr1004]=CONVERT(date,[tempdb].[dbo].[STAGE_TABLE].[date_col],0))) 
     |--Filter(WHERE:(isdate([tempdb].[dbo].[STAGE_TABLE].[date_col])=(1))) 
      |--Table Scan(OBJECT:([tempdb].[dbo].[STAGE_TABLE])) 

Там не кажется, намек/возможность зафиксировать первый запрос (так как он получает в одном лице предложения WHERE), но вы можете использовать который обрабатывает оба условия в одном прохождении сканирования.

SELECT * 
    FROM (SELECT * FROM STAGE_TABLE) X 
WHERE CAST(CASE WHEN ISDATE(DATE_COL) = 1 THEN DATE_COL ELSE NULL END AS DATE) < GETDATE() 
+0

Блестящий! Я все еще так слаб с планами запросов ... :(Итак, я предполагаю, что могу добавить подсказку, чтобы заставить dbe полностью оценить внутренний выбор в первую очередь? Если это так - любые советы о том, как я могу это сделать ? –

+0

Я не думаю, что есть подсказка - ответ обновлен – RichardTheKiwi

+0

Лучший опыт переполнения стека на сегодняшний день. –