【问题标题】:Cannot convert varchar to int or subtract them无法将 varchar 转换为 int 或减去它们
【发布时间】:2019-01-17 23:39:37
【问题描述】:

我有以下一组 SQL 语句。目的是找到每件商品的售价。

SELECT cost AS 'Price', disc AS 'Discount', (cost-disc) AS 'Selling Price' 
FROM SALE

问题是cost, scost, disc 列属于Varchar 数据类型。所以我尝试投列,但没有奏效。不,我尝试如下更改列数据类型:

UPDATE SALE 
SET cost = '0.0' 
WHERE cost IS NULL OR ISNUMERIC(cost) = 0;

ALTER TABLE SALE 
    ALTER COLUMN cost DECIMAL(12,0);

UPDATE SALE 
SET scost = '0.0' 
WHERE scost IS NULL OR ISNUMERIC(scost) = 0;

ALTER TABLE SALE 
    ALTER COLUMN scost DECIMAL(12,0);

UPDATE SALE 
SET disc = '0.0' 
WHERE disc IS NULL OR ISNUMERIC(disc) = 0;

ALTER TABLE SALE 
    ALTER COLUMN disc DECIMAL(12,0);

我在 SQL Server Management Studio 中遇到的错误:

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

如何解决这个问题?

【问题讨论】:

  • 检查 varchar 列中的逗号。 ISNUMERIC 不会找到它们,因为它会检查所有数字类型(包括钱)。
  • 错误信息提示 cost 是 int,而不是 varchar。尝试不带UPDATE 的 ALTER。

标签: sql sql-server sql-server-2008 sql-server-2005


【解决方案1】:

我建议创建一个具有所需结构的新表并将数据复制到新表中。然后重命名您的表。 下面是代码:

update SALE set cost='0.0' where cost='NULL' or cost IS NULL OR ISNUMERIC(cost) = 0;
update SALE set scost='0.0' where scost='NULL' or scost IS NULL OR ISNUMERIC(scost) = 0;
update SALE set disc='0.0' where disc='NULL' or disc IS NULL OR ISNUMERIC(disc) = 0;

CREATE TABLE SALENEW (cost decimal(18,2), scost decimal(18,2), disc decimal(18,2));

INSERT INTO SALENEW SELECT * FROM SALE;

EXEC sp_rename 'SALE', 'SALEBACKUP'; 
EXEC sp_rename 'SALENEW', 'SALE';

这会有所帮助。

【讨论】:

  • 是的,至少有了这个,现在一切正常。谢谢
【解决方案2】:

您应该修复数据。但我会推荐 explicit 转换:

select cost AS Price, disc AS Discount,
       (try_convert(decimal(20, 4), cost) - try_convert(decimal(20, 4), disc) ) as selling_price
from sale;

您不应该将数字存储为字符串。您可以通过执行以下操作查看是否有任何值无效:

select cost, disc
from sale
where try_convert(decimal(20, 4), cost) is null or
      try_convert(decimal(20, 4), disc) is null;

如果没有返回行,则转换它们:

alter table alter column cost decimal(20, 4);
alter table alter column disc decimal(20, 4);

注意:此答案使用decimal(20, 4),您可以使用其他相关类型,但十进制似乎适合示例数据。

编辑:

在早期版本的 SQL Server 中,我建议:

select cost AS Price, disc AS Discount,
       ((case when cost not like '%[^0-9.]%' and cost not like '%.%.%'
              then convert(decimal(20, 4), cost)
         end) -
        (case when disc not like '%[^0-9]%'  and cost not like '%.%.%'
              then try_convert(decimal(20, 4), disc)
         end)
       ) as selling_price
from sale;

您可以使用类似的逻辑。我不推荐isnumeric(),因为以下返回“1”——'$''.''3e4'——但这些都不能转换为小数。

【讨论】:

  • @Neetu - 您也可以使用 CONVERT 代替 2012 年提供的 TRY_CONVERT(提到您已标记为 2008 和 2005)
  • 它说:Msg 195, Level 15, State 10, Line 4 'decimal' 不是公认的内置函数名。
  • 使用 CONVERT 代替 try_convert,它显示 0 条记录。即使在餐桌上
【解决方案3】:

尝试转换为精度足以覆盖您的实际数据集的小数类型,例如

UPDATE SALE SET cost = '0.0' WHERE cost IS NULL OR ISNUMERIC(cost) = 0;
ALTER TABLE SALE ALTER COLUMN cost DECIMAL(12, 4);

您收到的确切错误消息似乎集中在字符串文字 0.0 不能转换为整数。但是,假设您尝试转换为小数,这听起来并不正确,在这种情况下,0.0 是一个完全可以接受的值。

【讨论】:

  • 嗨,现在它说:(0 行受影响)消息 5074,级别 16,状态 1,第 3 行对象“DF_SALE_scost”取决于列“成本”。消息 4922,级别 16,状态 9,第 3 行 ALTER TABLE ALTER COLUMN scost 失败,因为一个或多个对象访问此列。
  • @Neetu 这看起来像是一个错误,源于您的架构中的一个完全不同的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-28
  • 1970-01-01
  • 1970-01-01
  • 2013-11-27
  • 2017-12-11
  • 2013-07-21
相关资源
最近更新 更多