Проверить значения даты в поле NVarchar - PullRequest
0 голосов
/ 20 марта 2012

Привет! У меня есть приложение для составления отчетов, написанное на стороннем программном обеспечении. К сожалению, он хранит все значения как nvarchar и не проверяет ввод данных на стороне клиента, в результате я получаю следующую ошибку, когда

"Conversion failed when converting date and/or time from character string"  
System.Data.SqlClient.SqlException was unhandled by user code

или если я пытаюсь выполнить код в SSMS:

Msg 241, Level 16, State 1, Procedure settlement_list, Line 10
Conversion failed when converting date and/or time from character string.

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

   SELECT mat3_02_01, CONVERT(datetime, mat3_04_02), mat3_04_02 FROM lntmu11.matter3
   WHERE ISDATE(mat3_04_02) <> 1
   AND Coalesce(mat3_04_02, '') <> ''
   order by mat3_04_02 desc

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

У кого-нибудь есть предложения?

РЕДАКТИРОВАТЬ ---

Здесь хранится процедура (я знаю, где это уродливо)

SELECT mat_no, 'index'=matter.mat1_01_06,
  'insurance'=Replace(Replace(matter.mat1_03_01, 'INSURANCE COMPANY', ' '), 'COMPANY', ''), 
  matter.[status], 'casestage'=mat1_04_01, 'injured'=matter.MAT1_01_07, matter.client,
 'terms'=mat3_04_06, 'ClmAmt'=matter.mat1_07_01, 
  'ClmBal'=matter.mat1_07_03, 'SetTot'=matter3.MAT3_04_09, 'By'=mat3_03_02,
  'DtSttld'=mat3_04_02, 'SettlStg'=(MAT3_06_08 + ' / ' + MAT3_06_05)
FROM [lntmu11].matter3 inner join 
[lntmu11].matter ON [lntmu11].matter.sysid = [lntmu11].matter3.sysid
WHERE
(DateDiff(month, convert(datetime, MAT3_04_02, 101), GETDATE()) = @range 
  and mat3_03_02 like @by)
or
(mat3_04_06 like @by2 
  and DateDiff(month, convert(datetime, MAT3_04_02, 101),  GETDATE()) = @range) 
ORDER BY MAT3_03_02

Ответы [ 2 ]

2 голосов
/ 20 марта 2012

Проверьте запрос, где

  ISDATE(mat3_04_02) = 1 
  AND 
  Coalesce(mat3_04_02, '') = ''

Чтобы быть датой, она должна иметь значение.Но соответствует только второму условию, если оно не имеет значения.Пересечение (и) этих двух условий всегда ложно.

Если вы ищете ноль, тогда "mat3_04_02 is null", но все равно будет возвращать 0 строк.

Попробуйте

   SELECT mat3_02_01, CONVERT(datetime, mat3_04_02), mat3_04_02 
   FROM lntmu11.matter3
   WHERE ISDATE(mat3_04_02) = 1
   order by CONVERT(datetime, mat3_04_02) desc  

Я думаю, вы хотите, чтобы дата сортировалась ине отсортировано по строке

Вопрос начался с поиска допустимых дат и перешел на поиск неправильных дат

   SELECT mat3_02_01, mat3_04_02 
   FROM lntmu11.matter3
   WHERE ISDATE(mat3_04_02) = 0 
   AND mat3_04_02 is not null
   order by mat3_04_02) desc  
2 голосов
/ 20 марта 2012

Вы не можете форсировать порядок, в котором механизм запросов будет пытаться обработать оператор без предварительного сброса строк ISDATE() = 1 в таблицу #temp.Вы не можете гарантировать порядок обработки или короткое замыкание, даже если некоторые предложат использовать CTE или подзапрос, чтобы сначала отфильтровать плохие строки.Поэтому некоторые могут предложить:

;WITH x AS 
(
  SELECT mat3_02_01, mat3_04_02
  FROM Intmu11.matter3
  WHERE ISDATE(mat3_04_02) = 1
  AND mat3_04_02 IS NOT NULL -- edited!
)
SELECT mat3_02_01, CONVERT(DATETIME, mat3_04_02), mat3_04_02
FROM x
ORDER BY mat3_04_02 DESC;

И это может даже сработать сегодня.Но в долгосрочной перспективе действительно единственный способ гарантировать этот порядок обработки - в текущих версиях SQL Server - это:

SELECT mat3_02_01, mat3_04_02
  INTO #x
  FROM Intmu11.matter3
  WHERE ISDATE(mat3_04_02) = 1
  AND mat3_04_02 IS NOT NULL; -- edited!

SELECT mat3_02_01, CONVERT(DATETIME, mat3_04_02), mat3_04_02
  FROM #x
  ORDER BY mat3_04_02 DESC;

Задумывались ли вы о проверке значений на входе?Например, вы можете изменить место появления этой ошибки в приложении, ударив их по запястью, когда они вводят недопустимую дату, вместо того, чтобы наказывать человека, который выбирает их неверные данные.Если вы управляете обновлением / вставкой с помощью хранимой процедуры, вы можете сказать:

IF ISDATE(@mat3_04_02) = 0
BEGIN
    RAISERROR('Please enter a valid date.', 11, 1);
    RETURN;
END

Если вы не управляете манипулированием данными с помощью хранимых процедур, вы можете добавить проверочное ограничение ктаблица (после того, как вы очистили существующие неверные данные).

UPDATE Intmu11.matter3 SET mat3_04_02 = NULL
  WHERE ISDATE(mat3_04_02) = 0;

ALTER TABLE Intmu11 WITH NOCHECK 
  ADD CONSTRAINT mat3_04_02_valid_date CHECK (ISDATE(mat3_04_02)=1);

Таким образом, когда сообщение об ошибке всплывает пользователю, он увидит имя ограничения и, надеюсь, сможет сопоставить его сточка ввода данных на внешнем интерфейсе, которая не смогла:

Сообщение 547, уровень 16, состояние 0, строка 1
Оператор INSERT конфликтует с ограничением CHECK "mat3_04_02_valid_date".Конфликт произошел в базе данных «your_db», таблице «Intmu11.matter3», столбце «mat3_04_02».
Оператор завершен.

Или еще лучше, используйте правильный тип данных впервое место!Опять же, после обновления существующих неверных данных на NULL, вы можете сказать:

ALTER TABLE Intmu11.matter3 ALTER COLUMN mat3_04_02 DATETIME;

Теперь, когда кто-то пытается ввести не дату, он получит ту же ошибку, что и пользователи в настоящее время.получить, когда они пытаются выбрать неверные данные:

Msg 241, уровень 16, состояние 1, строка 1
Преобразование не удалось при преобразовании даты и / или времени из строки символов.

В SQL Server 2012 вы сможете обойти это с помощью TRY_CONVERT(), но вам все равно следует пытаться получить тип данных с самого начала.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...