问题
I have this query
SELECT
CASE WHEN dbo.CFE_PPHY.P77 IS NOT NULL OR dbo.CFE_PPHY.P77 <>''
THEN MONTH(dbo.CFE_PPHY.P77)
WHEN dbo.CFE_PPHY.P70 IS NOT NULL OR dbo.CFE_PPHY.P70 <>''
THEN MONTH(dbo.CFE_SERVICE_EVTS.C10_2)
ELSE COALESCE(CONVERT(VARCHAR,dbo.CFE_PPHY.P77)+
CONVERT(VARCHAR,dbo.CFE_SERVICE_EVTS.C10_2),'toto') END
AS CFELiasse_DateEffetEIRL_MM_N
FROM CFE_PPHY LEFT JOIN CFE_SERVICE_EVTS ON CFE_PPHY.colA = CFE_SERVICE_EVTS.colB
The ELSE
part is giving me headaches.
The columns CFE_PPHY.P77
and CFE_SERVICE_EVTS.C10_2
have date time format. I'm turning them into varchar. Yet when I'm running the query, I have the following error
Msg 245, Level 16, State 1, Line 1 Conversion failed when converting the varchar value 'toto' to data type int.
Obviously, I cannot turn toto
to an integer. Fair enough. However, from my point of view, I've converted the datetime format to a varchar format, so it should do the work.
Where am I wrong?
Thanks
回答1:
You have to convert all of your case expressions to varchar. SQL is deciding to case the field as int so 'toto' is invalid. If all expressions are converted to varchar this error should be solved.
http://blog.sqlauthority.com/2010/10/08/sql-server-simple-explanation-of-data-type-precedence/
回答2:
Have a closer look at your case
expression: in the first and second conditional branches you're returning MONTH(...
which is obviously integer.
But in third branch you're returning varchar
thus SQL server tries to convert it to int
according to data type of previous branches and failing to do it.
回答3:
Try like this,
SELECT CASE
WHEN dbo.CFE_PPHY.P77 IS NOT NULL
OR dbo.CFE_PPHY.P77 <> ''
THEN convert(VARCHAR, MONTH(dbo.CFE_PPHY.P77))
WHEN dbo.CFE_PPHY.P70 IS NOT NULL
OR dbo.CFE_PPHY.P70 <> ''
THEN convert(VARCHAR, MONTH(dbo.CFE_SERVICE_EVTS.C10_2))
ELSE COALESCE(CONVERT(VARCHAR, dbo.CFE_PPHY.P77) + CONVERT(VARCHAR, dbo.CFE_SERVICE_EVTS.C10_2), 'toto')
END AS CFELiasse_DateEffetEIRL_MM_N
FROM CFE_PPHY
LEFT JOIN CFE_SERVICE_EVTS ON CFE_PPHY.colA = CFE_SERVICE_EVTS.colB
回答4:
First, when converting to a string, always include a length (in SQL Server). The default length varies by context and may not be correct.
Second, the comparison of date/time values to ''
is not necessary. This is not really valid value for a date/time -- although it does get converted to a 0 which is 1900-01-01. The NULL
comparison should be sufficient. Otherwise, be explicit.
Third, string concatenation will return NULL
if any of the arguments are NULL
.
Fourth, table aliases make a query easier to write and to read.
As far as I can tell, your case
is a bit over complicated. In the ELSE
, we know that dbo.CFE_PPHY.P77
is NULL
, because of the first condition. So, how about:
SELECT (CASE WHEN p.P77 IS NOT NULL
THEN CAST(MONTH(p.P77) as VARCHAR(255))
WHEN p.P70 IS NOT NULL
THEN CAST(MONTH(e.C10_2) as VARCHAR(255))
ELSE 'toto'
END) AS CFELiasse_DateEffetEIRL_MM_N
FROM CFE_PPHY p LEFT JOIN
CFE_SERVICE_EVTS e
ON p.colA = e.colB;
来源:https://stackoverflow.com/questions/37615593/t-sql-different-datatype-possible-in-a-case