t-sql Different datatype possible in a case?

旧街凉风 提交于 2021-01-27 11:44:39

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!