【问题标题】:t-sql Different datatype possible in a case?t-sql 在一个案例中可能有不同的数据类型?
【发布时间】:2016-06-03 13:22:54
【问题描述】:

我有这个问题

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

ELSE 部分让我头疼。

CFE_PPHY.P77CFE_SERVICE_EVTS.C10_2 列具有日期时间格式。我正在把它们变成varchar。然而,当我运行查询时,出现以下错误

将 varchar 值“toto”转换为数据类型 int 时,消息 245,级别 16,状态 1,行 1 转换失败。

显然,我无法将toto 转换为整数。很公平。但是,从我的角度来看,我已经将 datetime 格式转换为 varchar 格式,所以它应该可以工作。

我哪里错了?

谢谢

【问题讨论】:

  • case 表达式返回列的值。 case 表达式的前两部分返回整数。月()。您不能在单个列中混合这样的数据类型。您还必须将它们转换为 varchar。您还真的需要在 varchars 上指定一个长度,而不仅仅是使用默认值。默认值为 30 或 1,具体取决于使用情况。您是否 100% 确定您知道哪个是哪个?如果 MS 在某些时候改变了你的代码,你的代码就会被破坏。
  • 问题是CASE 不支持多种数据类型,在前两个条件中,您以MONTH(blah) 的形式返回INT。要么将其转换为VARCHAR,要么不要使用“toto”。

标签: sql sql-server tsql datetime


【解决方案1】:

您必须将所有 case 表达式转换为 varchar。 SQL 决定将该字段大小写为 int,因此“toto”无效。如果所有表达式都转换为 varchar,则应该可以解决此错误。

http://blog.sqlauthority.com/2010/10/08/sql-server-simple-explanation-of-data-type-precedence/

【讨论】:

  • 嗨@joe-c,你的解释很清楚。积分是你的,先生。
【解决方案2】:

仔细查看您的 case 表达式:在第一个和第二个条件分支中,您返回的 MONTH(... 显然是整数。

但在第三个分支中,您返回 varchar,因此 SQL 服务器尝试根据先前分支的数据类型将其转换为 int,但未能成功。

【讨论】:

    【解决方案3】:

    这样试试,

    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
    

    【讨论】:

    • 嗨@stacknewuser,我想给你积分,但乔 C 来得更早。谢谢你的解释。
    • 不客气。我想解决你的问题,而不是在意积分
    【解决方案4】:

    首先,当转换为字符串时,总是包含一个长度(在 SQL Server 中)。默认长度因上下文而异,可能不正确。

    其次,没有必要将日期/时间值与'' 进行比较。对于日期/时间,这不是真正有效的值——尽管它确实被转换为 0,即 1900-01-01。 NULL 比较应该足够了。否则,请明确。

    第三,如果任何参数是NULL,字符串连接将返回NULL

    第四,表别名使查询更易于编写和阅读。

    据我所知,您的case 有点过于复杂。在ELSE 中,我们知道dbo.CFE_PPHY.P77NULL,因为第一个条件。那么,怎么样:

    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;
    

    【讨论】:

    • 嗨@gordon-linoff,感谢您的回答和所附的学习。我继续写你的书。很有意思,刚到第3章。想了想,我还要继续读下去,今晚就做吧。
    猜你喜欢
    • 2014-09-06
    • 1970-01-01
    • 1970-01-01
    • 2013-06-23
    • 1970-01-01
    • 2015-10-09
    • 2010-09-15
    • 2020-02-28
    • 1970-01-01
    相关资源
    最近更新 更多