修改 SQL 查询以将各种 NVARCHAR 字符串转换为日期/时间格式,某些情况下被设置为 NULL,即使它们不应该如此?

问题描述 投票:0回答:1

问题:

目标是将 SQL Server 中的临时表列 TempExpirationDate 从 NVARCHAR 更新为 DATETIME,然后使用这些值更新我的实际表。 列中的日期值有多种格式,需要转换为标准 DATETIME 格式。它基本上是一个从网站上废弃的列,必须经过大量清理才能采用日期时间格式。

待解决的问题: 尽管进行了多次调整,但某些特定的日期格式并未成功转换,即使它们看起来应该如此。

虽然大多数日期值已成功转换为 DATETIME,但特定情况(例如“2018 年 7 月 4 日”)仍会导致 NULL。 尽管对 CASE 条件进行了调整,但确定这些案例中失败的具体原因仍存在挑战。

我正在解析这样开始的数据(此日期列中不同类型值的示例)

2013-09-23 00:00:00
NULL
July 2  2022
NULL
May 5, 2015),
January 25, 2018.
March 7, 2019  
January 8, 2019  
September 8, 2019  
April 5  2021
January 8  2021
May 8, 2019 (
April 06  2023
January 14, 2023
July 15, 2022
July 4, 2018  
February 2016)  

我运行以下查询,通过删除我们看到的不同格式情况的特殊字符来帮助清理日期。

UPDATE #TempIntermediateResults
SET TempExpirationDate =
    CASE
        -- Do nothing if the date is in the format '2013-09-23 00:00:00'
        WHEN TempExpirationDate LIKE '%[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]%'
            THEN TempExpirationDate
        -- Leave as null if the date is null
        WHEN TempExpirationDate IS NULL
            THEN NULL
        -- Remove special characters for month and year format like 'February 2016)'
        WHEN CHARINDEX(')', TempExpirationDate) > 0
            THEN LTRIM(RTRIM(REPLACE(SUBSTRING(TempExpirationDate, 1, CHARINDEX(')', TempExpirationDate)), ')', '')))
            -- Remove special characters for formats like 'May 8, 2019 (' or 'May 5, 2015),'
        WHEN CHARINDEX('(', TempExpirationDate) > 0
            THEN LTRIM(RTRIM(REPLACE(SUBSTRING(TempExpirationDate, 1, CHARINDEX('(', TempExpirationDate)), '(', '')))
        -- Remove special characters for other cases, including "."
        ELSE LTRIM(RTRIM(REPLACE(REPLACE(TempExpirationDate, SUBSTRING(TempExpirationDate, PATINDEX('%[^a-zA-Z0-9 ]%', TempExpirationDate + '0'), 1), ''), '.', '')))
    END;

结果是这样的:

"2013-09-23 00:00:00"
NULL
"July 4 2018  "
"July 2  2022"
"February 2016"
NULL
"May 5, 2015"
"January 25 2018"
"March 7 2019  "
"January 8 2019  "
"September 8 2019  "
"April 5  2021"
"January 8  2021"
"May 8, 2019"
"April 06  2023"
"January 14 2023"
"July 15 2022"

接下来,我运行另一个更新查询来尝试将这些值更新为日期/时间格式。

-- Update the temporary table 
UPDATE #TempIntermediateResults
SET TempExpirationDate =
    CASE
        -- Existing conditions
        WHEN TRY_CAST(TempExpirationDate AS DATETIME) IS NOT NULL
            THEN TRY_CAST(TempExpirationDate AS DATETIME)
        WHEN CHARINDEX(',', TempExpirationDate) > 0
            THEN TRY_CAST(REPLACE(TempExpirationDate, ',', '') AS DATETIME)
        WHEN CHARINDEX(')', TempExpirationDate) > 0
            THEN TRY_CAST(REPLACE(SUBSTRING(TempExpirationDate, 1, CHARINDEX(')', TempExpirationDate)), ')', '') AS DATETIME)
        WHEN CHARINDEX(' ', LTRIM(RTRIM(TempExpirationDate))) > 0
            THEN TRY_CAST(REPLACE(LTRIM(RTRIM(TempExpirationDate)), ' ', '') AS DATETIME)
        ELSE '2000-12-31T00:00:00'   -- Default value if none of the conditions match. DID THIS AS A TEST VALUE TO TROUBLESHOOT IF I WOULD GET THIS DATE INSTEAD OF NULL.
    END;

但是,我的结果如下:

Sep 23 2013 12:00AM
Dec 31 2000 12:00AM
NULL
Jul  2 2022 12:00AM
Feb  1 2016 12:00AM
Dec 31 2000 12:00AM
May  5 2015 12:00AM
Jan 25 2018 12:00AM
NULL
NULL
NULL
Apr  5 2021 12:00AM
Jan  8 2021 12:00AM
May  8 2019 12:00AM
Apr  6 2023 12:00AM
Jan 14 2023 12:00AM
Jul 15 2022 12:00AM

我不知道为什么下面的值总是为空,而它应该正确格式化为日期/时间,或者如果我没有正确处理它,至少设置为“2000-12-31T00:00:00”。我认为这可能是空白,但我已经通过多种方式对其进行了测试,它似乎并没有影响空值的显示。

"July 4 2018  "
"March 7 2019  "
"January 8 2019  "
"September 8 2019  "

请帮忙。

sql sql-server formatting data-cleaning
1个回答
0
投票

我没有看到任何明显的问题,但我自己也做过类似的练习,可以提供一些提示。

当您进行数据清理时,以小步骤进行并保存中间结果以用于调试目的非常有帮助。

我的建议是,不要一遍又一遍地更新同一列,而是将每个步骤的结果保存到新的临时表中,或者将它们存储在自己的列中。

避免将多个操作合并为一个,例如

TRY_CAST(REPLACE(SUBSTRING(TempExpirationDate, 1, CHARINDEX(')', TempExpirationDate)), ')', '') AS DATETIME)
应该是两个单独的步骤:

  1. REPLACE(SUBSTRING(TempExpirationDate, 1, CHARINDEX(')', TempExpirationDate)), ')', '')
    - 删除无效字符
  2. TRY_CAST(...) - 尝试进行转换

如果您遵循这些建议,您应该能够很容易地发现问题。

© www.soinside.com 2019 - 2024. All rights reserved.