如何避免sql查询中的多次强制转换?

如何避免sql查询中的多次强制转换?,sql,tsql,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

我有以下用于转换数据的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 
脚本中还有很多例子,只是显示了第一个。我只能使用简单的文本脚本

更新 使用SQLServer2000

谢谢


Anders

您可以使用子查询或CTE:

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

这在您的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

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


这似乎是个问题。您所看到的多重铸造问题只是早期不良实践的结果。解决这些问题,您的问题就会消失。

类似的方法可能会奏效:

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)

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

这只是一个一次性脚本吗?如果是这样,并且您只是尝试在键入时进行保存,请按以下方式编写:

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
。。。然后进行全局搜索并替换为文本编辑器


或者,你可能担心的是,当一次可以做到的时候,你会在每行中多次施放吗?但是,如果这个脚本是一次性的,它真的重要吗?

在你的问题中,你提到你想要避免多次施放。如果您关心性能问题,那么不要担心。SQL不会多次转换该字段,即使脚本中多次有该字段

例如:

SELECT CONVERT(INT, '123'), CONVERT(INT, '123')
T-SQL只会在没有性能损失的情况下运行该方法


话虽如此,那么你唯一关心的另一件事就是打一串。。。如果是这样,那么Tony Andrews提到的xxx/find and replace注释就足够了。

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

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
这样,只有当它是一个数值时,它才会尝试执行强制转换,所以不会像其他人在评论中提到的那样出现强制转换异常

既然你说有更多的语句涉及,我猜你有更多的数字范围,得到不同的值。。。如果是这样的话,您可能可以使用第二个表,也可以是临时表,如果您像问题中所说的那样,仅限于要连接的SQL代码,其中包含最小值、最大值以及基于该值要显示的内容。当您需要计算非数值时会变得更加棘手,但这并非不可能


虽然没有看到完整的语句,但这是我能提供的最好的解决方案。

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

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

我真的不明白如何使用这个功能。。您能详细说明一下吗?WITH语句中的查询类似于视图,称为CTE。这只适用于SQL 2005/2008,顺便说一句。通过在CTE中强制转换它,您消除了在其他地方强制转换它的需要。不幸的是,我不能。有些结果是‘Q’、‘T’或类似的结果。我还没有创建它-只是必须修复它:/UPDATE语句中的强制转换会更改正在保存的数据类型。如果sni_kod应该是数据库中的文本,而不是整数呢?@Tony Andrews:你的RDBMS是什么?@Shahgholi.Ardalan:Oracle如何处理多个when案例。更新了问题以显示另一个案例。您在评论中说,sni_kod中的值可以是'Q'或'T'。因此,演员阵容无论如何都无法发挥作用。它只会给您一个强制转换异常。将varchar值“Q”转换为数据类型int时,转换失败。这确实解决了问题,但我发现Kevins的答案更符合我的要求。我非常喜欢您的重写,它更简单。非常感谢。使用您的代码作为基础来解决不同的铸造问题,谢谢。