如何在sql查询中避免多个CAST?

时间:2008-10-30 11:09:02

标签: sql tsql

我有以下用于转换数据的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 

脚本中有更多的案例,只显示第一个案例。我不能使用除简单文本脚本之外的任何东西。

更新 使用SQL Server 2000

由于

的Anders

9 个答案:

答案 0 :(得分:3)

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

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,所以你不会像其他人在评论中提到的那样获得强制转换异常。

既然你说有更多的陈述涉及,我猜你有更多的数字范围得到不同的价值......如果是这样,你可能能够使用第二个表(可以是一个临时的,如果,如你的问题所说,你只限于SQL代码)加入哪个有最小值,最大值,以及你想要显示的内容。当你需要评估非数字值时会变得更加棘手,但这并非不可能。

虽然没有看到完整的陈述,但这是我能提供的最佳陈述。

答案 1 :(得分: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

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

或许您可能会担心每次投射几次的性能?但同样,如果这个剧本是一次性的,那真的很重要吗?

答案 2 :(得分:2)

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

示例:

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

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

话虽如此,那么唯一可能有的另一个问题就是输入一堆......如果是这样的话,那么Tony Andrews提到的“xxx / find and replace”评论已经足够了。

答案 3 :(得分:1)

您可以使用子查询或CTE:

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

答案 4 :(得分:0)

这是否适用于您的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

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

这样的事可能会奏效:

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)

答案 7 :(得分:0)

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

答案 8 :(得分:0)

我看到有人发布了一个在from子句中加入子查询的解决方案。这是一个解决方案-just- 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