-4

Assuming that all values of MBR_DTH_DT evaluate to a Date data type other than the value '00000000', could the following UPDATE SQL fail when running on multiple processors if the CAST were performed before the filter by racing threads?

UPDATE  a
SET     a.[MBR_DTH_DT] = cast(a.[MBR_DTH_DT] as date)
FROM    [IPDP_MEMBER_DEMOGRAPHIC_DECBR] a
WHERE   a.[MBR_DTH_DT] <> '00000000'

I am trying to find the source of the following error

Error: 2014-01-30 04:42:47.67
   Code: 0xC002F210
   Source: Execute csp_load_ipdp_member_demographic Execute SQL Task
   Description: Executing the query "exec dbo.csp_load_ipdp_member_demographic" failed with the following error: "Conversion failed when converting date and/or time from character string.". Possible failure reasons: Problems with the query, "ResultSet" property not set correctly, parameters not set correctly, or connection not established correctly.
End Error

It could be another UPDATE or INSERT query, but the otehrs in question appear to have data that is proeprly typed from what I see,, so I am left onbly with the above.

Chad
  • 23,658
  • 51
  • 191
  • 321
  • 3
    This just makes no sense to me. Even if the string [MBR_DTH_DT] is a valid date you cannot put a date in a string (char) column. You have the same column on both sides of the set. Correction it will try an implicit conversion back to char. – paparazzo Jan 30 '14 at 21:34
  • 1
    This question appears to be off-topic because it lacks sufficient information to diagnose the problem. – Kermit Feb 02 '14 at 02:54
  • I agree that CASTING a varchar col to a date and assigning it back to itself is not a productive task, but this is what I find in production and I needed to determine if it was this SQL that was the cause of the problem. The heart of the question I believe is valid: Could a cast fail because it was applied to a record before it was filtered out. I believe that Aaron and other posts as well as my experience all suggest to me that yes, this is the case. Thanks to all that answered, even the angry ones that don't like the answer. – Chad Feb 02 '14 at 03:05
  • The fact is that SQL Server can try to perform the update before the filter for a variety of reasons and in a large number of different scenarios. In your case it may seem like removing parallelism may be the answer, but I can assure you that if you want to be protected from this scenario with or without hints in all future scenarios, you should use a `CASE` expression, as I demonstrated in my answer. `CASE` is the only way you can ensure that the conversion will be attempted *only* on values that meet the condition `ISDATE()=1`. – Aaron Bertrand Feb 02 '14 at 03:12
  • I gotcha. Put all this is a nice answer an i'll mark yours correct. – Chad Feb 02 '14 at 03:23
  • @ChadD all of this is irrelevant as an answer; it is merely refuting your bad answer. I've already explained in my answer that the way you solve this is to use a CASE expression. I don't really care if you mark my answer as the answer or not; your answer should be deleted because it is not right. – Aaron Bertrand Feb 02 '14 at 03:24
  • And I think I got the answer to what was really my question: Was a cast being appli3ed to a record that the filter targeted? Yes is the answer, and that's why it bombed. I went to far by theorizing that it was due to parallelism or that MAX PROC was valid solution, although I still wonder about FORC ORDER, which seems better if in fact it does guarantee that the WHERE will be performed before the SELECT. I haven't read up on it. – Chad Feb 02 '14 at 03:27
  • 1
    @ChadD FORCE ORDER has nothing to do with whether WHERE is processed before expressions in the SELECT clause - [see here](http://sqlfiddle.com/#!3/0b4c1/5). This has to do with JOIN processing. From [here](http://technet.microsoft.com/en-us/library/ms181714.aspx): `Specifies that the join order indicated by the query syntax is preserved during query optimization. Using FORCE ORDER does not affect possible role reversal behavior of the query optimizer.` Please don't make assumptions and then post accepted answers based on guesses and throwing darts at the wall. – Aaron Bertrand Feb 02 '14 at 03:28
  • You might find [this answer](http://stackoverflow.com/a/7029490/61305) useful. – Aaron Bertrand Feb 02 '14 at 04:24

2 Answers2

5

No, it simply sounds like you have bad data in the MBR_DTH_DT column, which is VARCHAR but should be a date (once you clean out the bad data).

You can identify those rows using:

SELECT MBR_DTH_DT 
  FROM dbo.IPDP_MEMBER_DEMOGRAPHIC_DECBR
  WHERE ISDATE(MBR_DTH_DT) = 0;

Now, you may only get rows that happen to match the where clause you're using to filter (e.g. MBR_DTH_DT = '00000000').

This has nothing to do with multiple processors, race conditions, etc. It's just that SQL Server can try to perform the cast before it applies the filter.

Randy suggests adding an additional clause, but this is not enough, because the CAST can still happen before any/all filters. You usually work around this by something like this (though it makes absolutely no sense in your case, when everything is the same column):

UPDATE dbo.IPDP_MEMBER_DEMOGRAPHIC_DECBR
  SET MBR_DTH_DT = CASE 
    WHEN ISDATE(MBR_DTH_DT) = 1 THEN CAST(MBR_DTH_DT AS DATE) 
    ELSE MBR_DTH_DT END
  WHERE MBR_DTH_DT <> '00000000';

(I'm not sure why in the question you're using UPDATE alias FROM table AS alias syntax; with a single-table update, this only serves to make the syntax more convoluted.)

However, in this case, this does you absolutely no good; since the target column is a string, you're just trying to convert a string to a date and back to a string again.

The real solution: stop using strings to store dates, and stop using token strings like '00000000' to denote that a date isn't available. Either use a dimension table for your dates or just live with NULL already.

Aaron Bertrand
  • 272,866
  • 37
  • 466
  • 490
  • Re: "You're just trying to convert a string to a date and back to a string again." OMG. You're right. I didn't realize the source and the target columns were the same. That's horrible. (this is production code written by long gone devs). And I agree whole heartedly on using appropriate data types up front. – Chad Jan 30 '14 at 21:54
-3

Not likely. Even with multiple processors, there is no guarantee the query will processed in parallel.

Why not try something like this, assuming you're using SQL Server 2012. Even if you're not, you could write a UDF to validate a date like this.

UPDATE  a
SET     a.[MBR_DTH_DT] = cast(a.[MBR_DTH_DT] as date)
FROM    [IPDP_MEMBER_DEMOGRAPHIC_DECBR] a
WHERE   a.[MBR_DTH_DT] <> '00000000' And IsDate(MBR_DTH_DT) = 1

Most likely you have bad data are are not aware of it.

Whoops, just checked. IsDate has been available since SQL 2005. So try using it.

Randy Minder
  • 47,200
  • 49
  • 204
  • 358
  • This doesn't help, because the `CAST` can still be attempted before the filter eliminates any rows where the `CAST` might fail. – Aaron Bertrand Jan 30 '14 at 21:17
  • Under what circumstances would SQL Server attempt to cast the value to a date before it first determines the row satisfies the Where clause? Taken to the extreme, if the table has a million rows and only 10 satisfy the Where clause, SQL Server could attempt to cast all million values to a date before it finds the 10 rows satisfying the query, which, of course, would be horribly inefficient. – Randy Minder Jan 30 '14 at 21:30
  • yes, that is possible, and it happens in a lot of cases. I've probably answered a dozen or more questions like this where this is exactly what happens. – Aaron Bertrand Jan 30 '14 at 21:31
  • 4
    Sure, you don't think I'm just making this up for fun, do you? I'll even double the offer: http://stackoverflow.com/questions/12305823/mssql-cast-varcharcolumn-to-int-in-select-gets-executed-before-where-clause/12305930#12305930 http://stackoverflow.com/questions/18601036/sql-is-rounding-my-decimal-on-cast/18601185#18601185 – Aaron Bertrand Jan 30 '14 at 21:35
  • 4
    Also here is a very simple repro - it uses a CTE to demonstrate that you can't always control the order of filters and expressions like CONVERT: http://sqlfiddle.com/#!3/0b4c1/1 – Aaron Bertrand Jan 30 '14 at 22:15
  • SQL Server 2012 has `try_convert` but the OP is on 2008 anyway. Relevant connect item [SQL Server should not raise illogical errors](http://connect.microsoft.com/SQLServer/feedback/details/537419/sql-server-should-not-raise-illogical-errors) – Martin Smith Feb 02 '14 at 16:50