在测试使用存储过程的应用程序时,我遇到了一个实际上已经修复过的错误。调试存储过程时,我发现中断的查询如下:
SET @LastSold = (SELECT last_sold_date
FROM movement.dbo.dv_store_items
WHERE Cast(store_number AS INT) = @Store
AND vendor_number = @Vendor
AND upc = @UPC
AND store_number <> 'CMPNY');
我收到的错误是:
Conversion failed when converting the varchar value 'CMPNY' to data type int
这个查询的奇怪之处在于,当我使用相同的标准在存储过程之外运行相同的查询时,它完全正常。更奇怪的是,这个存储过程工作得很好,直到我在表move.bo.dv_store_items上创建索引:
CREATE NONCLUSTERED INDEX [NCIX1] ON [dbo].[dv_store_items]
(
[upc] ASC,
[vendor_number] ASC,
[store_number] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF,
DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
GO
老老实实地,我不知道这有什么意义,所以任何帮助都会非常非常感激
答案 0 :(得分:1)
确保您不会遇到转换问题(alpha到整数,例如&#39; CMPY&#39;)的唯一万无一失的方法是使用TRY_CAST。如果无法进行演员表演(即,从&#39; CMPY&#39;到INT),这将返回NULL
。可在SQL Server 2012 +中使用。
SET @LastSold = (
SELECT
last_sold_date
FROM
movement.dbo.dv_store_items
WHERE
TRY_CAST(store_number AS INT)=@Store -- ensure you only select from actual integers
AND vendor_number = @Vendor
AND upc = @UPC
);
答案 1 :(得分:0)
问题在于我列出的索引:
CREATE NONCLUSTERED INDEX [NCIX1] ON [dbo].[dv_store_items]
(
[upc] ASC,
[vendor_number] ASC,
[store_number] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF,
DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
GO
应该是:
CREATE NONCLUSTERED INDEX [NCIX1] ON [dbo].[dv_store_items]
(
[store_number] ASC
)
INCLUDE ( [upc],
[last_sold_date],
[vendor_number]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
GO
正如Allan S. Hansen所说,原因是“WHERE中的操作顺序在两个版本中发生了变化”。
此外,TT。在评论中提出了一个很好的观点。通过完全过滤掉'CMPNY'值可以进一步改善这个查询,使我的WHERE子句中的那部分无关紧要:
CREATE NONCLUSTERED INDEX [NCIX1] ON [dbo].[dv_store_items]
(
[store_number] ASC
)
INCLUDE ( [upc],
[last_sold_date],
[vendor_number])
WHERE store_number <> 'CMPNY'
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
GO
答案 2 :(得分:0)
您的代码仍然容易出错,因为查询优化器的未来行为是不可预测的。 转换前检查数据。快速演示
declare @store_number varchar(100) = 'CMPNY';
declare @store int = 1;
SELECT 1 WHERE CASE @store_number WHEN 'CMPNY' THEN -@store ELSE cast( @store_number AS INT) END = @store;
-- no result, no error
set @store_number = cast(@store as varchar(100));
SELECT 1 WHERE CASE @store_number WHEN 'CMPNY' THEN -@store ELSE cast( @store_number AS INT) END = @store;
-- 1 row