У меня есть одна переменная 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 @Destination=@Temp
SELECT @Source AS Source, @Temp AS Temp, @Destination AS Destination
ИЗМЕНИТЬ здесь, с чем я собираюсь...
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
Ответ 1
Прежде всего, поскольку вы используете SQL Server 2005, вы должны поместить свой код в блок BEGIN TRY.....END TRY BEGIN CATCH....END CATCH
- блоки try/catch для T-SQL!
Во-вторых, для всех манипуляций с датами я бы всегда использовал формат ISO-8601, который будет работать независимо от того, что текущий формат даты установлен в 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 - вопреки тому, что, по-видимому, проповедует Books Online. Используйте YYYYMMDD или YYYY-MM-DDTHH: MM: SS вместо.
Спасибо, gbn!
Ответ 2
Вы можете гарантировать дату-месяц-год, используя SET DATEFORMAT.
Это означает, что ISDATE будет анализировать "15 -07-2009" с 15 июля 2009 года.
В противном случае ваш подход достаточно хорош с учетом внешних ограничений... но вы также можете переупорядочить в ANSI/ISO.
После ответа marc_s: "SET DATEFORMAT dmy" работает для большинства европейских настроек...
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