[英]Convert nvarchar(MAX) to datetime
我有一个包含几个字段nvarchar(MAX)
的表,它以dd/mm/yyyy
格式占用日期。
我运行此查询:
SELECT CONVERT(datetime,[Start Date],103)
FROM [YellowCard_NewDesign].[dbo].[vw_All_Requests]
我得到错误:
从nvarchar数据类型到datetime数据类型的转换导致值超出范围。
奇怪的是,当我运行以下查询时:
SELECT TOP 40 CONVERT(datetime,[Start Date],103)
FROM [YellowCard_NewDesign].[dbo].[vw_All_Requests]
它可以工作,但我不希望使用TOP X
。
我的表仅包含36条记录。 所以我认为没有不良数据。
20/03/2013
20/03/2013
10/03/2013
10/03/2013
11/03/2013
06/03/2013
06/03/2013
21/03/2013
12/03/2013
03/03/2013
18/03/2013
04/03/2013
28/02/2013
28/02/2013
28/02/2013
28/02/2013
31/01/2013
15/01/2013
23/01/2013
23/01/2013
31/01/2013
23/01/2013
30/01/2013
31/01/2013
24/01/2013
24/01/2013
24/01/2013
24/01/2013
24/01/2013
30/01/2013
23/01/2013
22/01/2013
23/01/2013
23/01/2013
23/01/2013
23/01/2013
有人可以帮我吗?
快速,轻松,轻松的方式将使您能够继续使用错误的数据类型,并允许各种垃圾进入表
SET DATEFORMAT DMY;
SELECT
-- other columns,
[Start Date] = CONVERT(DATETIME, CASE WHEN ISDATE([Start Date]) = 1
THEN [Start Date] END, 103)
FROM
dbo.vw_All_Requests;
现在,在这种情况下,对于不包含d/m/y
格式的有效日期的任何列值,它将返回NULL
。 如果要排除这些行而不是使用NULL
值包括它们,则可以添加WHERE
子句:
SET DATEFORMAT DMY;
SELECT
-- other columns,
[Start Date] = CONVERT(DATETIME, CASE WHEN ISDATE([Start Date]) = 1
THEN [Start Date] END, 103)
FROM
dbo.vw_All_Requests
WHERE ISDATE([Start Date]) = 1;
您无法执行此操作的原因...
SELECT CONVERT(DATETIME, [Start Date], 103)
FROM ...
WHERE ISDATE([Start Date]) = 1;
...是因为SQL Server可能会在过滤器之前尝试进行CONVERT
,从而导致与您现在遇到的错误相同的错误。 CASE
表达式(在大多数情况下)使您可以控制该评估顺序。
现在,当然,以d/m/y
格式有效的日期并不一定意味着它就是用户想要的。 如果您有一个美国人在7月4日输入07/04/2013
,那么您会错误地认为这是4月7日。 这就是为什么像d/m/y
和m/d/y
这样的区域格式不好的原因。
一种快速,轻松,轻松的方式,使您可以继续使用错误的数据类型, 但又需要进行更多的工作,从而防止更多的垃圾进入表中
您仍应遵循上述建议,并修复或删除所有不符合要求的数据,并至少添加一个检查约束,以使表中不再有垃圾:
ALTER TABLE dbo.SourceTable
ADD CONSTRAINT CK_SillyMaxColumnIsValidDate
CHECK (CONVERT(DATE, [Start Date], 103) >= '0001-01-01');
因此,以下插入将失败或成功:
-- these succeed:
INSERT dbo.SourceTable([Start Date]) SELECT '01/01/2005';
INSERT dbo.SourceTable([Start Date]) SELECT '25/01/2005';
GO
-- fails:
INSERT dbo.SourceTable([Start Date]) SELECT '01/25/2005';
GO
-- fails:
INSERT dbo.SourceTable([Start Date]) SELECT 'garbage';
这些故障可完全防止错误插入,并且仅允许将有效的d/m/y
字符串插入表中。 错误消息是:
消息241,级别16,状态1,第1行
从字符串转换日期和/或时间时转换失败。
正确的方式
首先,确定不良数据:
SELECT [Start Date]
FROM dbo.vw_All_Requests
WHERE ISDATE([Start Date]) = 0;
现在,修复该数据,无论它来自何处,以便您可以修复数据类型。 这可能意味着这些类型的语句的组合:
-- correct the date for specific bad values
UPDATE dbo.SourceTable
SET [Start Date] = '03/12/2012'
WHERE [Start Date] = 'whatever';
-- remove the value altogether for specific bad values
UPDATE dbo.SourceTable
SET [Start Date] = NULL
WHERE [Start Date] = 'whatever';
-- remove the row altogether for specific bad values
DELETE dbo.SourceTable
WHERE [Start Date] = 'whatever';
-- remove all rows with bad values
SET DATEFORMAT DMY;
DELETE dbo.SourceTable
WHERE ISDATE([Start Date]) = 0;
然后将DATE
列添加到源表中:
ALTER TABLE dbo.SourceTable
ADD StartDate -- no space!
DATE;
然后更新该列中的数据:
UPDATE dbo.SourceTable
SET StartDate = CONVERT(DATETIME, [Start Date], 103);
现在删除原始列(您可能需要调整包括该列的索引或引用该列的约束):
ALTER TABLE dbo.SourceTable
DROP COLUMN [Start Date];
现在,您可以更改新的列名:
EXEC sp_rename N'dbo.SourceTable.StartDate', 'Start Date', 'COLUMN';
或更改视图:
ALTER VIEW dbo.vw_All_Requests
AS
SELECT
...
[Start Date] = StartDate
或更改您的应用程序以使用新的更好的列名。 不要忘记更改所有数据类型参数以也使用正确的数据类型,并且在传递字符串文字时,请停止使用诸如d/m/y
类的区域格式。 像@Kaf,我宁愿yyyymmdd
,可从来没有被误解,但yyyy-mm-dd
会一直为工作DATE
-只是不DATETIME
,例如:
SET LANGUAGE FRENCH;
SELECT CONVERT(DATETIME, '2012-03-15');
结果:
消息242,级别16,状态3,第2行
转换日期类型为不合法的时间限制。
一些背景
请阅读这篇文章:
最后一点
请停止创建带有空格的列名或别名。 如果需要视觉分隔,请使用下划线。 这些都是用于列名的更好的选择,不要以任何方式改变含义,也不需要在每个引用旁边加上丑陋的方括号:
Start_Date
StartDate
在字符串类型字段中保存日期不是一个好主意。 但是,如果您现在必须处理这些问题,则可以使用isdate()
函数运行此查询以检查任何不良数据并进行修复:
SELECT [Start Date]
FROM [YellowCard_NewDesign].[dbo].[vw_All_Requests]
WHERE isdate([Start Date]) = 0
同样,如果在转换为日期类型之前获得非none culture specific
ISO format
的日期会更好。 如果它们都是dd/mm/yyyy
格式,则可以按照下面的ISO format
( 'yyyymmdd'
)获得它们。
declare @d varchar(max) = '20/03/2013'
select convert(datetime,right(@d,4) + substring(@d,4,2) + left(@d,2))
因此,您的实际查询将类似于:
SELECT CONVERT(datetime,right([Start Date],4) +
substring([Start Date],4,2) +
left([Start Date],2))
FROM [YellowCard_NewDesign].[dbo].[vw_All_Requests]
这与TOP 40无关。这意味着您在前40行中没有问题数据。
如果表中的数据较少,则可以简单地增加限制以找出发生错误的位置
例如:
SELECT TOP 100 CONVERT(datetime,[Start Date],103)
FROM [YellowCard_NewDesign].[dbo].[vw_All_Requests]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.