-1

I'm fixing an existing code but got stuck with it because SQL server keeps showing an error related to converting string to date and then bigint to date. so not sure which technique to use:

below is my code:

SELECT
c.WCFromDate
,c.WCToDate
,CONVERT(date, CAST(
                    CASE
                        WHEN c.WCFromDate = 0  THEN 19000101
                        WHEN SUBSTRING(CAST(c.WCFromDate as varchar(10)), 5, 2) = '00' AND RIGHT(c.WCFromDate,2) = '00'
                            THEN LEFT(c.WCFromDate, 4) * 10000 + 0101
                        WHEN SUBSTRING(CAST(c.WCFromDate as varchar(10)), 5, 2) = '02' AND RIGHT(c.WCFromDate,2) > '29'
                            THEN LEFT(c.WCFromDate, 4) * 10000 + 0228
                        WHEN SUBSTRING(CAST(c.WCFromDate as varchar(10)), 5, 2) < '13' AND RIGHT(c.WCFromDate,2) > '31'
                            THEN LEFT(c.WCFromDate, 4) * 10000 + 0101
                        WHEN SUBSTRING(CAST(c.WCFromDate as varchar(10)), 5, 2) > '12'
                            THEN LEFT(c.WCFromDate, 4) * 10000 + 0101
                        WHEN RIGHT(c.WCFromDate,2) = '00'
                            THEN LEFT(c.WCFromDate, 4) * 10000 + 0101
                        ELSE c.WCFromDate
                    END AS varchar(10))
        ) AS [Worker Compensation From Date]
,CONVERT(date, CAST(
                    CASE
                        WHEN c.WCToDate = 0 THEN 19000101
                        WHEN SUBSTRING(CAST(c.WCToDate as varchar(10)), 5, 2) = '00' AND RIGHT(c.WCToDate,2) = '00'
                            THEN LEFT(c.WCToDate, 4) * 10000 + 0101
                        WHEN SUBSTRING(CAST(c.WCToDate as varchar(10)), 5, 2) = '02' AND RIGHT(c.WCToDate,2) > '29'
                            THEN LEFT(c.WCToDate, 4) * 10000 + 0228
                        WHEN SUBSTRING(CAST(c.WCToDate as varchar(10)), 5, 2) < '13' AND RIGHT(c.WCToDate,2) > '31'
                            THEN LEFT(c.WCToDate, 4) * 10000 + 0101
                        WHEN SUBSTRING(CAST(c.WCToDate as varchar(10)), 5, 2) > '12'
                            THEN LEFT(c.WCToDate, 4) * 10000 + 0101
                        WHEN RIGHT(c.WCFromDate,2) = '00'
                            THEN LEFT(c.WCFromDate, 4) * 10000 + 0101
                        ELSE c.WCToDate
                    END AS varchar(10))
        ) AS [Worker Compensation To Date]
        FROM  ls3dwh.Claims c

To be more specific, all case when statements are working fine but the ELSE part is causing this error. I used ELSE NULL to find out more and noticed that all ELSE values are causing this error.

The column values are pretty simple, below screenshot can help:

all 4 columns

And here is some sample data from the first two columns. I used a select distinct:

   WCFromDate   WCToDate
   0        0
   19456601 20030000
   19580800 20300500
   19670000 0
   19840529 19840603
   19850314 19851115
   19851121 19910110
   19860217 19861112

The error I get is this:

Msg 241, Level 16, State 1, Line 1
Conversion failed when converting date and/or time from character string.

Dale K
  • 25,246
  • 15
  • 42
  • 71
Soben_SPDEV
  • 37
  • 1
  • 7
  • What, exactly, is the error? – Dale K Jun 22 '22 at 00:00
  • 1
    I'm sure there is a simpler approach. Sample data and desired results would be most helpful. – John Cappelletti Jun 22 '22 at 00:00
  • As per the question guide, please do not post images of code, data, error messages, etc. - copy or type the text into the question. Please reserve the use of images for diagrams or demonstrating rendering bugs, things that are impossible to describe accurately via text. – Dale K Jun 22 '22 at 00:03
  • 2
    Why don't you use `DATEFROMPARTS`? Also what are the data types of the columns? – Charlieface Jun 22 '22 at 00:06
  • Are you trying to convert strings like'19930325' to dates like '25/03/1993' ? – ahmed Jun 22 '22 at 00:10
  • thanks for the feedback everyone - I added some sample code and a screenshot of some larger sample because I couldn't attach the excel file (the post will be very long if I paste many rows obviously). – Soben_SPDEV Jun 22 '22 at 00:10
  • @Ahmed yes. so this 19930325 will need to be converted to 1993-03-25. the explicit cast or convert function doesnt work – Soben_SPDEV Jun 22 '22 at 00:14
  • For SQL Server 2019 it works, check this https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=fb050f2f2d1f54cb9095d7e1c29a232b – ahmed Jun 22 '22 at 00:16
  • 1
    I just noticed that you have values like '19670000', this value will cause an error with CAST as date – ahmed Jun 22 '22 at 00:25
  • So what are the actual data types of the column? `varchar` or `bigint` or something else? – Charlieface Jun 22 '22 at 00:42

3 Answers3

1

Your problem stems from the fact that you have different data types being returned, so the compiler attempts to coerce them all to the higher-precedence type, which is in this case date.

Instead you can just always return DATEFROMPARTS, or a conversion if necessary.

Assuming your data types really are varchar then you can clean up the code and simplify the various conditions like this:

SELECT
  c.WCFromDate
 ,c.WCToDate
 ,CASE
    WHEN c.WCFromDate = '0'
      THEN '19000101'
    WHEN SUBSTRING(c.WCFromDate, 5, 2) = '02' AND RIGHT(c.WCFromDate, 2) > '29'
      THEN DATEFROMPARTS(LEFT(c.WCFromDate, 4), 2, 28)
    WHEN SUBSTRING(CAST(c.WCFromDate, 5, 2) NOT BETWEEN '01' AND '13'
         OR RIGHT(c.WCFromDate, 2) NOT BETWEEN '01' AND '31'
      THEN DATEFROMPARTS(LEFT(c.WCFromDate, 4), 1, 1)
    ELSE
      TRY_CONVERT(date, c.WCFromDate, 112)
    END AS [Worker Compensation From Date]
 ,CASE
    WHEN c.WCToDate= '0'
      THEN '19000101'
    WHEN SUBSTRING(c.WCToDate, 5, 2) = '02' AND RIGHT(c.WCToDate, 2) > '29'
      THEN DATEFROMPARTS(LEFT(c.WCToDate, 4), 2, 28)
    WHEN SUBSTRING(CAST(c.WCToDate, 5, 2) NOT BETWEEN '01' AND '13'
         OR RIGHT(c.WCToDate, 2) NOT BETWEEN '01' AND '31'
      THEN DATEFROMPARTS(LEFT(c.WCToDate, 4), 1, 1)
    ELSE
      TRY_CONVERT(date, c.WCToDate, 112)
    END AS [Worker Compensation To Date]
FROM  ls3dwh.Claims c

If your data type is actually bigint then I suggest you use % and / division to get the different parts, rather than SUBSTRING.

Charlieface
  • 52,284
  • 6
  • 19
  • 43
0

Have you considered using IsDate(MyColumnValue) to check for valid dates, rather than parsing out over several case statements to check for date validity? That may make the process a little cleaner and easier to understand and debug, and may help you get the output you need. I just quick-checked and it works "as is" with values formatted like those you've shared.

Dale K
  • 25,246
  • 15
  • 42
  • 71
Brian S
  • 26
  • 3
  • hmm very good point. just tried it now and can see anomalies, e.g. 19456601 is added which returned 0. but how can I use this to sort this issue out? can you help please? – Soben_SPDEV Jun 22 '22 at 00:17
  • Maybe use IsDate to drive your case statements: CASE WHEN IsDate(DateField) THEN --output the date field ELSE ... --do whatever you need to do here to force a date that's acceptable for your application/purpose - here is where you might implement some of the calculations you used END AS DateToUse – Brian S Jun 22 '22 at 00:25
  • 1
    An answer should really solve OPs problem, rather than providing tips on how to do so - tips belong in comments. And as an aside its a case expression not a statement - which can be very important for the understanding of how it works. – Dale K Jun 22 '22 at 00:32
0

Try the following case expression:

Select case 
        when len(d)=8 and ((d%10000)=0 or (d%10000) >1231 or (d%100)>31 
        or (d%100)=0  or (d%10000/100)=0
        or ((d%10000/100) in(4,6,9,11) and d%100>30))
        then cast(cast(d+101-(d%10000) as varchar(10)) as date)
        
        when len(d)=8 and ((d%10000) between 230 and 299)
        then cast(cast(d+228-(d%10000) as varchar(10)) as date)
        
        when d=0 then cast('19000101' as date)
        else cast(d as date)
      end as dates
from dts

The expression will check for all possible errors (as you listed) in the date values and fix it according to your criteria.

See a demo from here.

ahmed
  • 9,071
  • 3
  • 9
  • 22