2009-07-16 4 views
10

У меня есть одна переменная char (8), отформатированная как ddmmyyyy в хранимой процедуре (качество и достоверность этого значения неизвестны и находятся за пределами моего контроля). Каков наилучший наиболее эффективный способ перемещения значения в переменную datetime и выдавать ошибку, если она недействительна datetime.лучший способ конвертировать и проверять строку даты

DECLARE @Source  char(8) 
DECLARE @Destination datetime 

SET @Source='07152009' 

--your solution here 


SELECT @Destination 

вот лучший способ, которым я мог думать:

DECLARE @Source    char(8) 
DECLARE @Temp    varchar(10) 
DECLARE @Destination  datetime 

set @Source='07152009' 
SET @Temp=LEFT(@Source,2)+'/'+SUBSTRING(@Source,3,2)+'/'+RIGHT(@Source,4) 

IF ISDATE(@Temp)!=1 
BEGIN 
    RAISERROR('ERROR, invalid date',16,1) 
END 
SET @[email protected] 

SELECT @Source AS Source, @Temp AS Temp, @Destination AS Destination 

EDIT вот что я собираюсь пойти с ...

DECLARE @Source    char(8) 
DECLARE @Destination  datetime 

set @Source='07152009' 
BEGIN TRY 
    SET @Destination=CONVERT(datetime,RIGHT(@Source,4)  -- YYYY 
             +LEFT(@Source,2)  -- MM 
             +SUBSTRING(@Source,3,2) -- DD 
          ) 
END TRY 
BEGIN CATCH 
    PRINT 'ERROR!!!' --I'll add a little more logic here and abort processing 
END CATCH 

SELECT @Source AS Source, @Destination AS Destination 
+0

Кажется, хорошо для меня, это то, что я написал бы тоже. Мне любопытно узнать, есть ли лучше. –

ответ

12

Прежде всего, поскольку вы используете SQL Server 2005, вы должны поместить свой код в , возможно, сбой в BEGIN TRY.....END TRY BEGIN CATCH....END CATCH блоки - блоки try/catch для T-SQL!

Во-вторых, для всех манипуляций с датами я бы всегда использовал ISO-8601 format, который будет работать независимо от того, какой формат текущей даты установлен в SQL Server.

ISO-8601 формат YYYYMMDD только за дату или YYYY-MM-DDTHH:MM:SS на дату со временем - так что я бы написать свой код, как:

BEGIN TRY 
    SET @Source='07152009' 
    SET @Temp = RIGHT(@Source, 4) +    -- YYYY 
       LEFT(@Source, 2) +    -- MM 
       SUBSTRING(@Source, 3, 2)  -- DD 

    IF ISDATE(@Temp)!=1 
    BEGIN 
     RAISERROR('ERROR, invalid date',16,1) 
    END 

    SET @Destination = CAST(@Temp AS DATETIME) 
END TRY 
BEGIN CATCH 
     -- handle error if something bombs out 
END CATCH 

Не следует полагаться на какой-либо конкретный формат даты быть установлен !! Отправьте мне свой код, и я попробую его в швейцарско-германской системе - я почти гарантирую, что он сломается, если вы вслепую предполагаете «en-US» и, таким образом, «mm/dd/yyyy» - это не такая же настройка всюду на этой планете.

К сожалению, SQL Server является довольно слабым временем обработки - возможно, это может быть точкой расширения, где использование сборки CLR внутри SQL Server имеет смысл, задействовать гораздо более богатые функции обработки даты в .NET?

Марк

PS: Кажется, формат ISO-8601 я знал YYYY-MM-DD не всегда работает в SQL Server - вопреки тому, что книги онлайн, кажется, проповедуют. Используйте YYYYMMDD или YYYY-MM-DDTHH: MM: SS вместо этого.
Спасибо, gbn!

+0

Это ANSI, а не ISO. ISO будет «1998-02-23T14: 23: 05 ' – gbn

+0

... без« T »и времени, yyyy-mm-dd по умолчанию для ANSI – gbn

+0

Моя система находится в контролируемой среде, не будет ни одной швейцарско-немецкой даты конверсии. Мне нравится идея try-catch.Я, вероятно, удалю IF ISDATE() и @Temp, а затем просто поймаю ошибку преобразования, если таковая есть при выполнении SET @ Destination = LEFT (@ Source, 2) + '/' + SUBSTRING (@ Source, 3,2) + '/' + RIGHT (@ Source, 4) –

6

Вы можете гарантировать дату-месяц-год, используя SET DATEFORMAT. Это означает, что ISDATE будет анализировать «15 -07-2009» с 15 июля 2009 года

В противном случае ваш подход достаточно хорош с учетом внешних ограничений ... но вы также можете переупорядочить в ANSI/ISO.

После ответа marc_s': "SET DATEFORMAT ДМГ" работает для большинства европейских установок ...

OK:

SET LANGUAGE british 
SELECT ISDATE('2009-07-15') --this is ansi says marc_s. It gives "zero" 
SELECT ISDATE('2009-07-15T11:22:33') --this really is ANSI and gives true 


SET LANGUAGE german 
SELECT ISDATE('2009-07-15') --false 
SELECT ISDATE('2009-07-15T11:22:33') --true 
+0

согласился - для большинства - но почему бы не использовать формат ISO-8601, который работает для ВСЕХ настроек SET DATEFORMAT ?? Просто играйте безопасно ..... –

+0

ISO-8601 действительно работает для всех настроек, но это не ISO: это ANSI, который вы указали http://stackoverflow.com/questions/1135746/sql-server-convert-string-to- datetime – gbn

+0

MS Books Online, похоже, не согласен: http://msdn.microsoft.com/en-us/library/ms190977%28SQL.90%29.aspx –

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