【问题标题】:How do I avoid multiple CASTs in sql query?如何避免在 sql 查询中出现多个 CAST?
【发布时间】:2008-10-30 11:09:01
【问题描述】:

我有以下用于转换数据的 sql 查询,但是否可以将 int 的值保存在某个变量中以避免多次转换?

update prospekts set sni_kod = case

when 
    cast(sni_kod as int) >= 1000 and cast(sni_kod as int) <= 1499 
    or cast(sni_kod as int) >= 1600 and cast(sni_kod as int) <= 2439
then '1'
when 
    cast(sni_kod as int) >= 7000 and cast(sni_kod as int) <= 7499 
then 'W'
else
     sni_kod
end 

脚本中还有很多 when-case,仅显示第一个。除了简单的文本脚本之外,我不能使用任何东西。

更新 使用 SQL Server 2000

谢谢

安德斯

【问题讨论】:

  • 您在评论中说 sni_kod 中的值可以是“Q”或“T”。结果 CAST 无论如何都不起作用。它只会给你一个演员表例外。 “将 varchar 值 'Q' 转换为数据类型 int 时转换失败。”

标签: sql tsql


【解决方案1】:

好的...这是我对您的代码的重写...

UPDATE prospekts SET sni_kod = 
    CASE
        WHEN ISNUMERIC(@sni_kod)=1 THEN
            CASE 
                WHEN cast(@sni_kod as int) BETWEEN 1000 AND 1499 OR cast(@sni_kod as int) BETWEEN 1600 AND 2439 THEN '1'
                WHEN cast(@sni_kod as int) BETWEEN 7000 AND 7499 THEN 'W'
                ELSE @sni_kod
            END
        ELSE @sni_kod
    END

这样,如果它是一个数值,它只会尝试执行 CAST,因此您不会像其他人在 cmets 中提到的那样遇到强制转换异常。

由于您说涉及的语句更多,我猜您有更多的数字范围可以获得不同的值...如果是这种情况,您也许可以使用第二个表(可以是临时的,如果,就像您的问题所说,您仅限于 SQL 代码)加入具有最小值、最大值以及您希望基于此显示的内容。当您需要评估非数字值时会变得更加棘手,但这并非不可能。

虽然没有看到完整的声明,但这是我能提供的最好的。

【讨论】:

  • 我真的很喜欢你的重写,它更简单。谢谢!
  • 使用您的代码作为基础来解决不同的投射问题,谢谢。
【解决方案2】:

这只是一个一次性脚本吗?如果是这样,并且您只是想节省打字时间,请写成:

update prospekts set sni_kod = case
when 
    xxx >= 1000 and xxx <= 1499 
    or xxx >= 1600 and xxx <= 2439
then '1'
when 
    xxx >= 7000 and xxx <= 7499 
then 'W'
else
     sni_kod
end

...然后进行全局搜索并用文本编辑器替换。

或者您可能担心每行投射几次的性能,而一次可能会这样做?但是,如果这个脚本是一次性的,那真的很重要吗?

【讨论】:

  • 这确实解决了问题,但我确实发现 Kevins 的回答更符合我的要求
【解决方案3】:

在您的问题中,您提到要“避免多次投射”。如果您担心性能问题,请不要担心。 SQL 不会多次转换该字段(即使您在脚本中多次使用它)。

例子:

SELECT CONVERT(INT, '123'), CONVERT(INT, '123')

T-SQL 只会运行该方法一次(没有性能损失)。

话虽如此,那么您唯一可能担心的其他问题就是输入一堆......如果是这样的话,那么 Tony Andrews 提到的“xxx / 查找和替换”评论就足够了。

【讨论】:

    【解决方案4】:

    您可以使用子查询或 CTE:

    With xxx AS (
         i_sni_kod = cast(sni_kod as int)
         ...)
    UPDATE prospekts set sni_kod = case 
        when i_sni_kod >= 100 ...
    

    【讨论】:

    • 我不太明白如何使用这个功能..你能详细说明一下吗?
    • WITH语句中的查询类似于视图,称为CTE。这仅适用于 SQL 2005/2008,顺便说一句。通过将其投射到 CTE 中,您无需将其投射到其他地方。
    【解决方案5】:

    这在您的 DBMS 中有效吗?

    update (select prospekts.*, cast(sni_kod as int) sni_kod_int from prospekts)
    set sni_kod = case
    when 
        sni_kod_int >= 1000 and sni_kod_int <= 1499 
        or sni_kod_int >= 1600 and sni_kod_int <= 2439
    then 1
    else
         sni_kod
    end
    

    【讨论】:

    • 在 UPDATE 语句中执行 CAST 会更改正在保存的数据类型。如果 sni_kod 应该是数据库中的文本而不是整数怎么办?
    • @Tony Andrews:你的 RDBMS 是什么?
    • @Shahgholi.Ardalan:甲骨文
    【解决方案6】:

    这似乎是您的模型有问题,而不是您的查询。为什么该列不只是一个 int?

    这似乎是一个shoe or glass bottle 的问题。您看到的多重投射问题只是早期不良做法的结果。解决这些问题,您的问题就会消失。

    【讨论】:

    • 不幸的是我不能。一些结果是“Q”、“T”或类似的。我还没有创建它 - 只需要修复它:/
    【解决方案7】:

    这样的事情可能会奏效:

    update prospekts set sni_kod = 1
    from prospekts
        join (select prospekts.primarykey, cast(prospekts.sni_kod as int) as sni_kod_int from prospekts) p2 on prospekts.primarykey = p2.primarykey
    WHERE (p2.sni_kod_int >=1000 and p2.sni_kod_int <= 1499)
        or (p2.sni_kod_int >=1600 and p2.sni_kod_int <= 2439)
    

    【讨论】:

    • 这将如何与多个 when-cases 一起工作。 (更新了问题以显示另一个案例)
    【解决方案8】:

    您显示的 UPDATE 语句;我假设它只会运行一次?如果它第二次运行,那么当它找到上一次运行中添加的“W”时,转换为 int 将失败。 这里最好的选择是更改 sni_kod 列的数据类型。也许你可以解释一下这个列是什么,为什么它需要同时保存 int 和 varchar 数据? 最后,SQL server 几乎可以肯定只进行一次强制转换。它非常适合在查询中查找重复的表达式和子查询并且只运行一次。如果不确定,请查看执行计划。

    【讨论】:

      【解决方案9】:

      我看到有人发布了一个在 from 子句中加入子查询的解决方案。这是一个在 from 子句中使用子查询的解决方案。

      DECLARE @MyTable TABLE
      (
        theKey int identity(1,1) PRIMARY KEY,
        theValue varchar(30)
      )
      ------    
      INSERT INTO @MyTable SELECT '1'
      INSERT INTO @MyTable SELECT '2'
      INSERT INTO @MyTable SELECT '3'
      ------
      
      UPDATE sub
      SET theValue =
        CASE
          WHEN convertedvalue % 2 = 0 THEN 'even'
          ELSE theValue
        END
      FROM
      (
        SELECT
          CASE
            WHEN Isnumeric(theValue) = 1
            THEN convert(int, theValue)
            ELSE null
          END as convertedValue, *
        FROM @MyTable mt
      ) as sub
      ------
      SELECT *
      FROM @MyTable
      

      【讨论】:

        猜你喜欢
        • 2020-09-22
        • 1970-01-01
        • 1970-01-01
        • 2011-05-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-14
        • 2020-03-24
        • 1970-01-01
        相关资源
        最近更新 更多