如何在T-SQL中标准化一列混合日期格式

时间:2014-08-20 11:04:06

标签: sql sql-server tsql date datetime

在SQL Server中有一个表,其中包含一个带有日期数据的varchar列。不幸的是,日期是一系列不同的格式。

2012-05-01
27/05/2012 
07MAY2014
19/07/13   

可能还有其他人,但到目前为止我所遇到过的一切。

我需要将这些列入datetime列到另一个表中,因此我一直在尝试将它们选为标准日期时间值。起初,我认为这很容易:

UPDATE myTable 
SET myDateColumn = CONVERT(DATETIME, myDateColumn, 103)
WHERE ISDATE(myDateColumn) = 0

但问题是SQL Server将dd/mm/yydd/mm/yyyy视为单独的格式。前者是代码3,后者是代码103.因此,无论以何种方式运行更新,它都会以相反的格式窒息。

我是否可以根据日期格式选择/更新,并将所有这些日期转换为单一有效的DateTime格式?

4 个答案:

答案 0 :(得分:3)

我的猜测是你只需要尝试区分不同的类并以适当的方式处理每个案例。像这样:

declare @tab table (d varchar(20))
insert @tab values ('2012-05-01'),('27/05/2012'),('07MAY2014'),('19/07/13')

select 
    case 
        when isnumeric(left(d,4)) = 1 then cast(d as date) 
        when len(d) = 10 then convert(date, d, 103) 
        when len(d) = 8 then convert(date, d, 3) 
        when charindex('/',d) = 0 and isnumeric(d) = 0 then convert(date, d, 106) 
    end as [date]
from @tab

输出:

date
----------
2012-05-01
2012-05-27
2014-05-07
2013-07-19

它可能效率不高,但我认为这是一次性操作。我没有把它写成更新语句,但查询应该很容易适应,如果可能的话,你应该考虑将转换后的日期添加为新的正确日期时间列。

编辑:这是相应的更新声明:

update @tab
set d = 
    case 
        when isnumeric(left(d,4)) = 1 then cast(d as date) 
        when len(d) = 10 then convert(date, d, 103) 
        when len(d) = 8 then convert(date, d, 3) 
        when charindex('/',d) = 0 and isnumeric(d) = 0 then convert(date, d, 106) 
    end 
from @tab

答案 1 :(得分:1)

在SQL Server 2012中,您可以使用try_convert()。否则,您可以进行多次更新:

UPDATE myTable 
    SET myDateColumn = CONVERT(DATETIME, myDateColumn, 103)
    WHERE ISDATE(myDateColumn) = 0 AND MyDateColumn like '[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9]';

UPDATE myTable 
    SET myDateColumn = CONVERT(DATETIME, myDateColumn, 3)
    WHERE ISDATE(myDateColumn) = 0 AND MyDateColumn like '[0-9][0-9]/[0-9][0-9]/[0-9][0-9]';

注意:where子句可能适用于update。它不适用于select。您可能还需要使用case

UPDATE myTable 
    SET myDateColumn = (CASE WHEN ISDATE(myDateColumn) = 0 AND MyDateColumn like '[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9]'

                             THEN CONVERT(DATETIME, myDateColumn, 103)
                             ELSE myDateColumn
                        END)
    WHERE ISDATE(myDateColumn) = 0 AND MyDateColumn like '[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-0]'

此外,您将值重新放在同一列中,以便覆盖原始数据 - 并且您有另一个隐式转换回字符串我强烈建议您使用{{{}向表中添加另一列1}}数据类型并将正确输入的值放在那里。

答案 2 :(得分:1)

这非常可怕,但它适用于您的示例:

DECLARE @DodgyDates TABLE (
    DateString VARCHAR(50));
INSERT INTO @DodgyDates VALUES ('2012-05-01');
INSERT INTO @DodgyDates VALUES ('27/05/2012'); 
INSERT INTO @DodgyDates VALUES ('07MAY2014');
INSERT INTO @DodgyDates VALUES ('19/07/13');
SELECT * FROM @DodgyDates;
--SELECT CONVERT(DATE, DateString) FROM @DodgyDates;--Fails
WITH DateDeconstruct AS (
    SELECT
        *,
        CASE
            WHEN DateString LIKE '____-__-__' THEN DateString
            WHEN DateString LIKE '__/__/____' THEN RIGHT(DateString, 4) + '-' + SUBSTRING(DateString, 4, 2) + '-' + LEFT(DateString, 2)
            WHEN DateString LIKE '__/__/__' THEN '20' + RIGHT(DateString, 2) + '-' + SUBSTRING(DateString, 4, 2) + '-' + LEFT(DateString, 2)
            WHEN DateString LIKE '_________' THEN RIGHT(DateString, 4) + '-' + CONVERT(VARCHAR(2), DATEPART(MM, DateString)) + '-' + LEFT(DateString, 2)
        END AS FixedString
    FROM
        @DodgyDates)
SELECT
    DateString AS OriginalDate,
    FixedString AS FixedDate,
    CONVERT(DATE, FixedString) AS ConvertedDate
FROM
    DateDeconstruct;

结果是:

OriginalDate    FixedDate   ConvertedDate
2012-05-01  2012-05-01  2012-05-01
27/05/2012  2012-05-27  2012-05-27
07MAY2014   2014-5-07   2014-05-07
19/07/13    2013-07-19  2013-07-19

答案 3 :(得分:0)

首先,您可以将所有数据转换为另一种格式,例如110 USA date fromat,然后再次使用所需格式更新整个表格。

相关问题