[英]SQL Error Converting Data to Int When I am Not Asking It To
I have the following SQL statement. 我有以下SQL语句。 In it I need to convert some numbers stored as varchar to decimal in order to sum them.
在其中我需要将存储为varchar的一些数字转换为十进制,以便对它们求和。
When I run this SQL against my constraints I get this message: 当我针对我的约束运行此SQL时,我收到以下消息:
Msg 245, Level 16, State 1, Line 1 Conversion failed when converting the varchar value '1635.34' to data type int.
当将varchar值'1635.34'转换为数据类型int时,消息245,级别16,状态1,行1转换失败。
Which baffles me because I am casting my data as decimal. 这让我感到困惑,因为我将数据转换为十进制数据。 It also baffles me because when I use different constraints that have the same type of data in the field (
1234.56
type of format) it works. 它也让我感到困惑,因为当我使用在字段中具有相同类型数据的不同约束(
1234.56
格式)时,它可以工作。 That data is in the TotalPremium
field. 该数据位于
TotalPremium
字段中。
(My logic is a bit complex so that is why SQL statement is complex. I am posting all of it for clarity sake. Also, redesigning database table field type is not an option at this point.) (我的逻辑有点复杂,所以这就是为什么SQL语句很复杂。为了清楚起见,我发布了所有这些。另外,此时重新设计数据库表字段类型不是一个选项。)
SELECT Account_No, version_num, LineOfBus, ProductNo, QuoteNo, Sum(Cast(TotalPremium as Decimal(16,2))) TotalPremium
FROM
(SELECT t.Account_No, t.version_num,
CASE
WHEN t.PackageIndicator = '1' THEN 'Package' Else t.Lob
END AS LineOfBus,
t.ProductNo, t.QuoteNo, Cast(COALESCE(t.TotalPremium,0) as decimal(16,2)) TotalPremium
FROM uAccountProductInfo as T
WHERE t.version_num IN
(SELECT sqVersionNumber.version_num
FROM
/* this captures unique package product records (or just stand alone records as well) */
(SELECT DISTINCT sqUnique.version_num, Count(sqUnique.version_num) VersionCount
FROM
/* grab list of all uniquer version, product, quote combinations (use distinct to combine package */
(SELECT DISTINCT version_num, productNo, quoteNo
FROM uAccountProductInfo
WHERE Account_No = '1172014' /* pass as parameter */
AND ProductNo IN ('6472930', '6474927') /* pass as parameter */
AND QuoteNo IN ('724185-01', '881957-08') /* pass as parameter */
) AS sqUnique
GROUP BY version_num
HAVING Count(version_num) = 2 /* pass as variable based on number of products, quotes */
) as sqVersionNumber
)
AND t.Account_no = '1172014' /* pass as parameter */
AND t.ProductNo IN ('6472930', '6474927') /* pass as parameter */
AND t.QuoteNo IN ('724185-01', '881957-08') /* pass as parameter */) as sqLOB
GROUP BY Account_No, version_num, LineOfBus, ProductNo, QuoteNo
Cast t.TotalPremium
to decimal before coalescing. 在合并之前将
t.TotalPremium
为十进制。 Your query is doing coalesce
on a string and an integer, then casting the result to decimal. 您的查询正在对字符串和整数进行
coalesce
,然后将结果转换为十进制。 Try using
0.0 instead of
0 as well.
Try using
0.0 instead of
0 as well.
edit I do not actually think using 0.0
rather than 0
is a good idea, aside from readability. 编辑我实际上并不认为使用
0.0
而不是0
是一个好主意,除了可读性。 If that is the goal, cast it to the same decimal datatype. 如果这是目标,则将其强制转换为相同的十进制数据类型。 Otherwise, this could be construed as a datatype dominant over
decimal
. 否则,这可以被解释为优于
decimal
的数据类型。 0
as int
or varchar
should not take precedence over our value casted to a decimal. 0
作为int
或varchar
不应优先于我们的值转换为小数。
You could use isnull()
instead of coalesce()
, though it would still be better practice to use the same datatype as RexMaison points out. 您可以使用
isnull()
而不是coalesce()
,尽管使用与RexMaison指出的相同数据类型仍然是更好的做法。
create table t (TotalPremium varchar(16));
insert into t values (''),(null),('1635.34');
/* no error */
select isnull(t.TotalPremium,0)
from t;
/* no error */
select coalesce(t.TotalPremium,'0')
from t;
/* error */
select coalesce(t.TotalPremium,0)
from t;
rextester demo: http://rextester.com/OHEJ71310 rextester演示: http ://rextester.com/OHEJ71310
The problem is that SQL Server does not guarantee the order of evaluation of operations. 问题是SQL Server不保证操作评估的顺序。 You clearly have something improper in the field.
你在这个领域显然有一些不合适的东西。 In SQL Server 2012+, use
try_convert()
: 在SQL Server 2012+中,使用
try_convert()
:
SELECT Sum(try_convert(decimal(16, 2), TotalPremium ))) as TotalPremium
In earlier versions, use case
: 在早期版本中,用
case
:
SELECT Sum(case when isnumeric(TotalPremium) = 1 then convert(decimal(16, 2), TotalPremium)) end) as TotalPremium
isnumeric()
is not perfect, but it should be good enough for your purposes. isnumeric()
并不完美,但它应该足以满足您的目的。
Just posting final code that worked after incorporating elements of all 3 answers. 只需在合并所有3个答案的元素后发布最终代码。
SELECT Account_No, version_num, LineOfBus, ProductNo, QuoteNo,
SUM(CASE
WHEN ISNUMERIC(TotalPremium) = 1 THEN CONVERT(decimal(16,2),TotalPremium)
END) As TotalPremium
FROM
(SELECT t.Account_No, t.version_num,
CASE
WHEN ISNull(t.PackageIndicator,'0') = '1' THEN 'Package' Else t.Lob
END AS LineOfBus,
t.ProductNo, t.QuoteNo,
ISNull(CASE
WHEN ISNUMERIC(t.TotalPremium) = 1 THEN CONVERT(decimal(16,2),t.TotalPremium)
END, 0) TotalPremium
FROM uAccountProductInfo as T
WHERE t.version_num IN
(SELECT sqVersionNumber.version_num
FROM
/* this captures unique package product records (or just stand alone records as well) */
(SELECT DISTINCT sqUnique.version_num, Count(sqUnique.version_num) VersionCount
FROM
/* grab list of all uniquer version, product, quote combinations (use distinct to combine package */
(SELECT DISTINCT version_num, productNo, quoteNo
FROM uAccountProductInfo
WHERE Account_No = '1172014' /* pass as parameter */
AND ProductNo IN ('6472930', '6474927') /* pass as parameter */
AND QuoteNo IN ('724185-01', '881957-08') /* pass as parameter */
) AS sqUnique
GROUP BY version_num
HAVING Count(version_num) = 2 /* pass as variable based on number of products, quotes */
) as sqVersionNumber
)
AND t.Account_no = '1172014' /* pass as parameter */
AND t.ProductNo IN ('6472930', '6474927') /* pass as parameter */
AND t.QuoteNo IN ('724185-01', '881957-08') /* pass as parameter */) as sqLOB
GROUP BY Account_No, version_num, LineOfBus, ProductNo, QuoteNo
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.