Validate date stored as a string as a complete, valid date

  • I have an upstream table where birth_date is stored as a string, YYYYMMMDD.  The data is very dirty. 

    I need to convert it to a date value, only if it is a complete date, otherwise NULL.  No imputed dates, i.e. assuming MMDD = 01-01, etc.  No load errors due to the dirty data.

    I wish there was an option to ISDATE that would validate for a complete date w/o imputation.

    Is the below the best approach?  This feel kludgy to me but I can't think of a better way.

    DECLARE @t TABLE (s VARCHAR(8))

    INSERT INTO @t
    VALUES
    ('foo')
    ,('2018')
    ,('201802')
    ,('20180230')
    ,('  2018')
    ,('2018----')
    ,('----01--')
    ,('20181225')

    SELECT s
      ,ISDATE(s) AS IsDate
      ,CASE
        WHEN(LEN(LTRIM(s)) != 8) THEN NULL
        WHEN(ISDATE(s)=0) THEN NULL
        ELSE CAST(s AS DATE)  -- or CONVERT(DATE,s,112) ???
       END AS MyDate
    FROM @t

  • Here is another way of writing the logic
    😎


    USE TEEST;
    GO
    SET NOCOUNT ON;

    DECLARE @t TABLE (s VARCHAR(8))

    INSERT INTO @t
    VALUES
    ('foo')
    ,('2018')
    ,('201802')
    ,('20180230')
    ,('20180228')
    ,(' 2018')
    ,('2018----')
    ,('----01--')
    ,('20181225')

    SELECT X.s
    ,ISDATE(s) AS IsDate
    ,DATEADD(DAY,1 - NULLIF(1 + SIGN(DATALENGTH(TRIM(X.s)) - 8),0),TRY_CONVERT(DATE,X.s,112)) AS MyDate
    FROM @t X;

  • If you're on SQL 2016 (or even SQL 2012), just use TRY_CAST:


    SELECT s
    ,TRY_CAST(s AS date) AS MyDate
    FROM @t

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

  • I'm not sure how you're populating your upstream table but, if you're using BCP or BULK INSERT, learn how to use the error parameters to simply sequester the rows with the bad dates into a rework file.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Eirikur Eiriksson - Tuesday, December 18, 2018 12:55 AM

    Here is another way of writing the logic
    😎


    USE TEEST;
    GO
    SET NOCOUNT ON;

    DECLARE @t TABLE (s VARCHAR(8))

    INSERT INTO @t
    VALUES
    ('foo')
    ,('2018')
    ,('201802')
    ,('20180230')
    ,('20180228')
    ,(' 2018')
    ,('2018----')
    ,('----01--')
    ,('20181225')

    SELECT X.s
    ,ISDATE(s) AS IsDate
    ,DATEADD(DAY,1 - NULLIF(1 + SIGN(DATALENGTH(TRIM(X.s)) - 8),0),TRY_CONVERT(DATE,X.s,112)) AS MyDate
    FROM @t X;

    Hi @Eirikur,

    An appropriate emoji 😉

    I'm reminded of a previous life when I used to view obfuscated Perl.  Hmmm, I'll have to think about this, and the poor developer who may have to support this code down the road.

    But it looks to me like it's using the same approach as mine, i.e. using LEN or DATALENGTH as a proxy to mean "a complete date" (assuming it then converts as a date).  As before, I wish there was a way to coax ISDATE to only return 1 only if the input is a complete date w/o further imputation.

    I certainly need to hit the doc for SIGN, DATALENGTH, and TRY_CONVERT, so thanks for that.

    Scott

  • ScottPletcher - Tuesday, December 18, 2018 11:12 AM

    If you're on SQL 2016 (or even SQL 2012), just use TRY_CAST:


    SELECT s
    ,TRY_CAST(s AS date) AS MyDate
    FROM @t

    Hi Scott,

    Your parents named you well 😀

    I'll hit the doc on TRY_CAST, but that in and of itself does not give me the desired results:

    DECLARE @t TABLE (s VARCHAR(8))

    INSERT INTO @t
    VALUES
    ('foo')
    ,('2018')
    ,('201802')
    ,('20180230')
    ,(' 2018')
    ,('2018----')
    ,('----01--')
    ,('20181225')

    SELECT s
    ,ISDATE(s) AS IsDate
    ,CASE
      WHEN(LEN(LTRIM(s)) != 8) THEN NULL
      WHEN(ISDATE(s)=0) THEN NULL
      ELSE CAST(s AS DATE) -- or CONVERT(DATE,s,112) ???
     END AS MyDate
    ,TRY_CAST(s AS DATE) AS ScottPDate
    FROM @t

    See rows 3 & 5.

    Scott

  • Jeff Moden - Tuesday, December 18, 2018 12:26 PM

    I'm not sure how you're populating your upstream table but, if you're using BCP or BULK INSERT, learn how to use the error parameters to simply sequester the rows with the bad dates into a rework file.

    Hi Jeff,

    I'm not populating the upstream table, another team is.

    The data is health data, and I suspect (this is just conjecture) that the hospitals send flat files to my government department, and the proverbial "they" are using BCP, BULK INSERT, or some similar means to import the data as-is.

    We seem to have a culture here that we should retain the garbage so we "know what was sent", rather than cleanse the data.  Or perhaps "they" are just lazy.  Anyway, this leaves the downstream developer or analyst to deal with the garbage.

    This is the same data for which I posted https://www.sqlservercentral.com/Forums/2011818/Request-code-review-for-UDF-ContainsControlChar-and-CleanString, on which you've commented.

    Scott

  • Scott In Sydney - Thursday, December 20, 2018 11:30 PM

    Hi Scott,
    Your parents named you well 😀

    I'll hit the doc on TRY_CAST, but that in and of itself does not give me the desired results:

    DECLARE @t TABLE (s VARCHAR(8))

    INSERT INTO @t
    VALUES
    ('foo')
    ,('2018')
    ,('201802')
    ,('20180230')
    ,(' 2018')
    ,('2018----')
    ,('----01--')
    ,('20181225')

    SELECT s
    ,ISDATE(s) AS IsDate
    ,CASE
      WHEN(LEN(LTRIM(s)) != 8) THEN NULL
      WHEN(ISDATE(s)=0) THEN NULL
      ELSE CAST(s AS DATE) -- or CONVERT(DATE,s,112) ???
     END AS MyDate
    ,TRY_CAST(s AS DATE) AS ScottPDate
    FROM @t

    See rows 3 & 5.

    Scott

    Try combining the two:

    SELECT s
    ,ISDATE(s) AS IsDate
    ,CASE
        WHEN LTRIM(s) NOT LIKE '[1-2][0-9][0-9][0-9][1-2][0-9][1-3][0-9]' THEN CAST(NULL AS date)
        ELSE TRY_CAST(s AS date)
    END AS MyDate
    FROM @t

    John

  • Scott In Sydney - Thursday, December 20, 2018 11:24 PM

    Eirikur Eiriksson - Tuesday, December 18, 2018 12:55 AM

    Here is another way of writing the logic
    😎


    USE TEEST;
    GO
    SET NOCOUNT ON;

    DECLARE @t TABLE (s VARCHAR(8))

    INSERT INTO @t
    VALUES
    ('foo')
    ,('2018')
    ,('201802')
    ,('20180230')
    ,('20180228')
    ,(' 2018')
    ,('2018----')
    ,('----01--')
    ,('20181225')

    SELECT X.s
    ,ISDATE(s) AS IsDate
    ,DATEADD(DAY,1 - NULLIF(1 + SIGN(DATALENGTH(TRIM(X.s)) - 8),0),TRY_CONVERT(DATE,X.s,112)) AS MyDate
    FROM @t X;

    Hi @Eirikur,

    An appropriate emoji 😉

    I'm reminded of a previous life when I used to view obfuscated Perl.  Hmmm, I'll have to think about this, and the poor developer who may have to support this code down the road.

    But it looks to me like it's using the same approach as mine, i.e. using LEN or DATALENGTH as a proxy to mean "a complete date" (assuming it then converts as a date).  As before, I wish there was a way to coax ISDATE to only return 1 only if the input is a complete date w/o further imputation.

    I certainly need to hit the doc for SIGN, DATALENGTH, and TRY_CONVERT, so thanks for that.

    Scott

    Added some comments to explain the code
    😎


    USE TEEST;
    GO
    SET NOCOUNT ON;

    DECLARE @t TABLE (s VARCHAR(8))

    INSERT INTO @t
    VALUES
    ('foo')
    ,('2018')
    ,('201802')
    ,('20180230')
    ,('20180228')
    ,(' 2018')
    ,('2018----')
    ,('----01--')
    ,('20181225')
    ;
    SELECT
     X.s
     -- ISDATE returns 1 for both full dates and year only
    ,ISDATE(s) AS IsDate
    -- TRY_CONVERT follows the same logic as ISDATE, if the input is year then
    -- it "produces" 1st Jan of the year.
    ,TRY_CONVERT(DATE,X.s,112) AS TC_OUT
    -- Get the length of the column value
    ,DATALENGTH(TRIM(X.s)) AS DLEN
    -- Return 0 if 8 characters, otherwise -1
    ,SIGN(DATALENGTH(TRIM(X.s)) - 8) AS Is8Char
    -- Shift the sign by + 1
    ,1 + SIGN(DATALENGTH(TRIM(X.s)) - 8) AS Is8CharShift
    -- Produce a NULL output if the length does not match
    ,NULLIF(1 + SIGN(DATALENGTH(TRIM(X.s)) - 8),0) AS IsNullIfShort
    -- Pulling it all together, the DATEADD will either add 0 days or return NULL
    -- if the input is too short
    ,DATEADD(DAY,1 - NULLIF(1 + SIGN(DATALENGTH(TRIM(X.s)) - 8),0),TRY_CONVERT(DATE,X.s,112)) AS MyDate
    FROM @t X;


  • SELECT s
        s2
        ,TRY_CAST(s2 AS DATE) AS ScottPDate
    FROM @t
    CROSS APPLY (
        SELECT LTRIM(RTRIM(s)) AS s1
    ) AS ca1
    CROSS APPLY (
        SELECT CASE WHEN LEN(s1) = 4 THEN s1 + '0101'
            WHEN LEN(s1) = 6 THEN s1 + '01'
            ELSE s1 END AS s2
    ) AS ca2

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

  • Scott In Sydney - Thursday, December 20, 2018 11:30 PM

    ScottPletcher - Tuesday, December 18, 2018 11:12 AM

    If you're on SQL 2016 (or even SQL 2012), just use TRY_CAST:


    SELECT s
    ,TRY_CAST(s AS date) AS MyDate
    FROM @t

    Hi Scott,

    Your parents named you well 😀

    I'll hit the doc on TRY_CAST, but that in and of itself does not give me the desired results:

    DECLARE @t TABLE (s VARCHAR(8))

    INSERT INTO @t
    VALUES
    ('foo')
    ,('2018')
    ,('201802')
    ,('20180230')
    ,(' 2018')
    ,('2018----')
    ,('----01--')
    ,('20181225')

    SELECT s
    ,ISDATE(s) AS IsDate
    ,CASE
      WHEN(LEN(LTRIM(s)) != 8) THEN NULL
      WHEN(ISDATE(s)=0) THEN NULL
      ELSE CAST(s AS DATE) -- or CONVERT(DATE,s,112) ???
     END AS MyDate
    ,TRY_CAST(s AS DATE) AS ScottPDate
    FROM @t

    See rows 3 & 5.

    Scott

    I realize that Scott Pletcher already provided a solution but there may be a simplification.  I'm just confused by your statement of "See rows 3 & 5" but you didn't say a thing about row 1.
    data:image/png;base64,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

    It looks like you're saying that row 3, which resolves to the YYYYMM format, should resolve to a date for the first of the given month.
    It also looks like you're saying that row 5, which resolves to YYYY, should not be considered as a valid date for the 1st of January for the given year.
    Part of the confusion is that row 2 also resolves to just YYYY and yet you brought no attention to that.

    So, let me ask... what are the explicit rules?  Are they...
    1.  If the characters resolve to YYYYMMDD and it's a valid date, return the converted date.
    2.  If the characters resolve to YYYYMM      and it's a valid year and month, return the converted date as a "first of he month" date.
    3.  If the characters resolve to YYYY            return a NULL regardless if it's a valid year or not.
    4.  Otherwise, return NULL

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Jeff Moden - Monday, December 24, 2018 10:41 AM

    Scott In Sydney - Thursday, December 20, 2018 11:30 PM

    ScottPletcher - Tuesday, December 18, 2018 11:12 AM

    If you're on SQL 2016 (or even SQL 2012), just use TRY_CAST:


    SELECT s
    ,TRY_CAST(s AS date) AS MyDate
    FROM @t

    Hi Scott,

    Your parents named you well 😀

    I'll hit the doc on TRY_CAST, but that in and of itself does not give me the desired results:

    DECLARE @t TABLE (s VARCHAR(8))

    INSERT INTO @t
    VALUES
    ('foo')
    ,('2018')
    ,('201802')
    ,('20180230')
    ,(' 2018')
    ,('2018----')
    ,('----01--')
    ,('20181225')

    SELECT s
    ,ISDATE(s) AS IsDate
    ,CASE
      WHEN(LEN(LTRIM(s)) != 8) THEN NULL
      WHEN(ISDATE(s)=0) THEN NULL
      ELSE CAST(s AS DATE) -- or CONVERT(DATE,s,112) ???
     END AS MyDate
    ,TRY_CAST(s AS DATE) AS ScottPDate
    FROM @t

    See rows 3 & 5.

    Scott

    I realize that Scott Pletcher already provided a solution but there may be a simplification.  I'm just confused by your statement of "See rows 3 & 5" but you didn't say a thing about row 1.
    data:image/png;base64,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

    It looks like you're saying that row 3, which resolves to the YYYYMM format, should resolve to a date for the first of the given month.
    It also looks like you're saying that row 5, which resolves to YYYY, should not be considered as a valid date for the 1st of January for the given year.
    Part of the confusion is that row 2 also resolves to just YYYY and yet you brought no attention to that.

    So, let me ask... what are the explicit rules?  Are they...
    1.  If the characters resolve to YYYYMMDD and it's a valid date, return the converted date.
    2.  If the characters resolve to YYYYMM      and it's a valid year and month, return the converted date as a "first of he month" date.
    3.  If the characters resolve to YYYY            return a NULL regardless if it's a valid year or not.
    4.  Otherwise, return NULL

    FYI, here's my last post, with the changes for yyyy and yyyymm incorporated into the code:


    SELECT s
        s2
        ,TRY_CAST(s2 AS DATE) AS ScottPDate
    FROM @t
    CROSS APPLY (
        SELECT LTRIM(RTRIM(s)) AS s1
    ) AS ca1
    CROSS APPLY (
        SELECT CASE WHEN LEN(s1) = 4 THEN s1 + '0101'
            WHEN LEN(s1) = 6 THEN s1 + '01'
            ELSE s1 END AS s2
    ) AS ca2

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

  • Now all I have to do is get the OP to confirm and/or clarify the requirements according to the questions I asked.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

Viewing 13 posts - 1 through 12 (of 12 total)

You must be logged in to reply to this topic. Login to reply