将字符串转换为日期SQLSERVER

时间:2018-10-02 13:14:51

标签: sql sql-server

我的源表在单列中有dmymdy格式的记录,并且是nvarchar数据类型。如何将这些数据转换为datetime并从每个记录中提取月份?

Source Data
StartDate: 06/13/2018,
           30/05/2018

Expected result:
Month:6
      5

2 个答案:

答案 0 :(得分:1)

类似于注释中的讨论,但不知道数据中的日期实际上是没有用的。尽管我提供了答案,但列名非常重要。 一个叫做Guessed的原因是猜测。

WITH VTE AS(
    SELECT *
    FROM (VALUES('13/01/2018','gb'),
                ('12/01/2018','gb'),
                ('12/01/2018','us'),
                ('04/27/2018','us'),
                ('04/05/2018','us')) V(D,f))
SELECT *,
       CONVERT(datetime,V.D, CASE V.F WHEN 'us' THEN 101 WHEN 'gb' THEN 103 END) AS ActualDate,
       DATEPART(MONTH,CONVERT(datetime,V.D, CASE V.F WHEN 'us' THEN 101 WHEN 'gb' THEN 103 END)) AS ActualMonth,
       CASE WHEN TRY_CONVERT(datetime,V.D,103) IS NULL THEN TRY_CONVERT(datetime,V.D,101) ELSE TRY_CONVERT(datetime,V.D,103) END AS GuessedDate,
       DATEPART(MONTH,CASE WHEN TRY_CONVERT(datetime,V.D,103) IS NULL THEN TRY_CONVERT(datetime,V.D,101) ELSE TRY_CONVERT(datetime,V.D,103) END) AS GuessedMonth
FROM VTE V;

请注意,这些查询得到的结果大不相同,在猜测的列中,2个错误

个人而言,建议您首先修复数据类型。如果您不能可靠地确定数据丢失的日期格式。您唯一可以知道数据是否采用特定格式的是前两个值之一具有等于或大于13的值(例如'13/12/2018'必须是dmy格式,而'05/27/2017'必须是mdy)。出于猜测,我将dmy设为“默认”格式。您可能比这更了解您的数据(并假设默认为mdy),但是,考虑到数据选择,我想您的猜测与任何人都一样。

无论如何,祝你好运。

答案 1 :(得分:0)

如果您有标识格式的列,请使用@Lamu的方法。否则,您可以检查日期字段:如果第一个或第二个字段> 12,则知道该字段为日期。如果我们假设所有记录的格式均为X/Y/Z,其中Z为年份,X和Y为月份和日期(或日期和月份),则可以执行以下操作:

WITH
    -- sample data: we can infer the format from the first 2 records ,
    -- but not the last
    SourceData(ds) AS
    (
        SELECT '6/13/2018' UNION ALL
        SELECT '30/05/2018' UNION ALL
        SELECT '12/01/2017'
    )
    ,WithSlashPositions(ds, Slash1_Position, Slash2_Position) AS
    (
        SELECT 
            ds, 
            CHARINDEX('/', ds, 1),
            CHARINDEX('/', ds, CHARINDEX('/', ds, 1) + 1)
        FROM SourceData
    )
    ,WithFields(ds, Slash1_Position, Slash2_Position, f1, f2, f3) AS
    (
        SELECT *,
            CONVERT(INT, SUBSTRING(ds, 1, Slash1_Position - 1)),
            CONVERT(INT, SUBSTRING(ds, Slash1_Position + 1, Slash2_Position - Slash1_Position - 1)),
            CONVERT(INT, SUBSTRING(ds, Slash2_Position + 1, LEN(ds)))
        FROM WithSlashPositions
    )
SELECT *,
    CASE
        WHEN f1 > 12 -- we know f1 is the day
            THEN CONVERT(DATE, ds, 103)
        WHEN f2 > 12 -- we know f2 is the day
            THEN CONVERT(DATE, ds, 101)
    END AS guess
FROM WithFields

返回这些记录:

+------------+-----------------+-----------------+----+----+------+------------+
|     ds     | Slash1_Position | Slash2_Position | f1 | f2 |  f3  |    guess   |
+------------+-----------------+-----------------+----+----+------+------------+
| 6/13/2018  |               2 |               5 |  6 | 13 | 2018 | 2018-06-13 |
| 30/05/2018 |               3 |               6 | 30 |  5 | 2018 | 2018-05-30 |
| 12/01/2017 |               3 |               6 | 12 |  1 | 2017 | NULL       |
+------------+-----------------+-----------------+----+----+------+------------+

请注意,最后一条记录(12/01/2017)返回null,因为我们无法推断其格式。