我在存储过程中有一个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
答案 0 :(得分:12)
首先,既然您正在使用SQL Server 2005,那么您应该将可能失败的代码放入BEGIN TRY.....END TRY BEGIN CATCH....END 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处理日期相当薄弱 - 也许这可能是一个扩展点,在SQL Server中使用CLR程序集是有意义的,可以利用.NET中更丰富的日期处理函数?
马克
PS:似乎我知道的ISO-8601格式YYYY-MM-DD在SQL Server中并不总是有用 - 与在线书籍似乎宣传的相反。使用YYYYMMDD或YYYY-MM-DDTHH:MM:SS代替 谢谢,gbn!
答案 1 :(得分:6)
您可以使用SET DATEFORMAT保证日期 - 月 - 年订单。 这意味着ISDATE将于2009年7月15日解析'15 -07-2009'
否则,考虑到外部限制,您的方法已经足够好了......但您也可以重新订购ANSI / ISO。
在marc_s'回答之后:“SET DATEFORMAT dmy”适用于大多数欧洲设置......
行:
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