处理 varchar 日期转换时超出范围的值
Dealing with out of range value on varchar date conversion
我正在尝试将输入到我们系统中的日期作为 YYYYMMDD
格式的文本转换为日期。不幸的是,我们的系统允许使用任何一个月的 31 日来表示这是该月的最后一天,对于某些功能(如应计利息等)来说很重要。
我有一个显示为 20160931
的日期,显然无法通过
转换
CONVERT(DATETIME, CONVERT(CHAR(8), [FIELD]))
并抛出值超出范围错误。
如何克服这个问题,以便将其转换为正确的值,在这种情况下 30/09/2016
?
您可以尝试这样的操作:
DECLARE @YourDate VARCHAR(100)='20160231';
SELECT CAST(y+m+dNew AS DATE)
FROM (VALUES(LEFT(@YourDate,4)
,SUBSTRING(@YourDate,5,2)
,SUBSTRING(@YourDate,7,2))) AS Parts(y,m,d)
CROSS APPLY
(
SELECT CASE WHEN CAST(m AS INT) IN(4,6,9,11) AND CAST(d AS INT)>30 THEN '30'
ELSE CASE WHEN CAST(m AS INT)=2 AND CAST(d AS INT)>28 THEN '28' ELSE d END
END AS dNew
) AS NewDay
大约在 2 月 29 日,您还需要检查年份是否要除以 4:-)
更新
现在轮到我改进@Irawan 的技术了:-)
既然SQLServer 2005没有EOMONTH
的功能,不过还是让SQLServer来计算比较好(2月29日隐式解决!),我建议这样做:
DECLARE @YourDate VARCHAR(100)='20160231';
SELECT DATEADD(SECOND,-1,DATEADD(MONTH,1,CAST(y+m+'01' AS DATETIME)))
FROM (VALUES(LEFT(@YourDate,4)
,SUBSTRING(@YourDate,5,2)
,SUBSTRING(@YourDate,7,2))) AS Parts(y,m,d)
无论如何,这将在本月的最后一秒交付...
如果你想要一个普通的 DATE
(没有时间),你可以将 SECOND
更改为 DAY
,这将首先跳到 DATE
第一天的午夜=35=]下一个 个月然后再往前一天...
更新 2 如果有效则使用现有日期
语法简单...
DECLARE @YourDate VARCHAR(100)='20160229';
SELECT CASE WHEN ISDATE(@YourDate)=1 THEN @YourDate
ELSE DATEADD(SECOND,-1,DATEADD(MONTH,1,CAST(LEFT(@YourDate,4) + SUBSTRING(@YourDate,5,2) +'01' AS DATETIME)))
END AS CorrectDate;
适应@Shnugo 的技术,我觉得还是离开SQL 决定月底比较好。因此:
SELECT eomonth(CAST(y+m+'01' AS DATE))
FROM (VALUES(LEFT(@YourDate,4)
,SUBSTRING(@YourDate,5,2)
,SUBSTRING(@YourDate,7,2))) AS Parts(y,m,d)
将给出“2016-02-29”而不是“2016-02-28”,二月份的常数为“28”
我正在尝试将输入到我们系统中的日期作为 YYYYMMDD
格式的文本转换为日期。不幸的是,我们的系统允许使用任何一个月的 31 日来表示这是该月的最后一天,对于某些功能(如应计利息等)来说很重要。
我有一个显示为 20160931
的日期,显然无法通过
CONVERT(DATETIME, CONVERT(CHAR(8), [FIELD]))
并抛出值超出范围错误。
如何克服这个问题,以便将其转换为正确的值,在这种情况下 30/09/2016
?
您可以尝试这样的操作:
DECLARE @YourDate VARCHAR(100)='20160231';
SELECT CAST(y+m+dNew AS DATE)
FROM (VALUES(LEFT(@YourDate,4)
,SUBSTRING(@YourDate,5,2)
,SUBSTRING(@YourDate,7,2))) AS Parts(y,m,d)
CROSS APPLY
(
SELECT CASE WHEN CAST(m AS INT) IN(4,6,9,11) AND CAST(d AS INT)>30 THEN '30'
ELSE CASE WHEN CAST(m AS INT)=2 AND CAST(d AS INT)>28 THEN '28' ELSE d END
END AS dNew
) AS NewDay
大约在 2 月 29 日,您还需要检查年份是否要除以 4:-)
更新
现在轮到我改进@Irawan 的技术了:-)
既然SQLServer 2005没有EOMONTH
的功能,不过还是让SQLServer来计算比较好(2月29日隐式解决!),我建议这样做:
DECLARE @YourDate VARCHAR(100)='20160231';
SELECT DATEADD(SECOND,-1,DATEADD(MONTH,1,CAST(y+m+'01' AS DATETIME)))
FROM (VALUES(LEFT(@YourDate,4)
,SUBSTRING(@YourDate,5,2)
,SUBSTRING(@YourDate,7,2))) AS Parts(y,m,d)
无论如何,这将在本月的最后一秒交付...
如果你想要一个普通的 DATE
(没有时间),你可以将 SECOND
更改为 DAY
,这将首先跳到 DATE
第一天的午夜=35=]下一个 个月然后再往前一天...
更新 2 如果有效则使用现有日期
语法简单...
DECLARE @YourDate VARCHAR(100)='20160229';
SELECT CASE WHEN ISDATE(@YourDate)=1 THEN @YourDate
ELSE DATEADD(SECOND,-1,DATEADD(MONTH,1,CAST(LEFT(@YourDate,4) + SUBSTRING(@YourDate,5,2) +'01' AS DATETIME)))
END AS CorrectDate;
适应@Shnugo 的技术,我觉得还是离开SQL 决定月底比较好。因此:
SELECT eomonth(CAST(y+m+'01' AS DATE))
FROM (VALUES(LEFT(@YourDate,4)
,SUBSTRING(@YourDate,5,2)
,SUBSTRING(@YourDate,7,2))) AS Parts(y,m,d)
将给出“2016-02-29”而不是“2016-02-28”,二月份的常数为“28”