我在SQL Server 2008中遇到了一个误导性的错误,我想知道是否有人能解释我发生了什么?
我有一个类似这样的存储过程:
declare @cross_reference table (
context varchar(20) not null
, value1 varchar(10) not null
, value2 varchar(10) not null
)
insert into @cross_reference values ('map', 'from_value', 'to_value')
insert into @cross_reference values ('map', 'from_value', 'to_value')
insert into @cross_reference values ('map', 'from_value_xxxxx', 'to_value_xxxxxxx')
select
t1.field1
, t1.field2
, xref.value2
from table_1 t1
inner join table_2 t2 on t2.id = t1.id
left join @cross_reference xref on xref.context = 'map' and xref.value1 = t2.map_id
实际的存储过程更复杂,但这是要点。
运行SP后,我会在“字符串或二进制数据被截断”错误之前得到一堆输出行。错误中的特定行引用指向上面主SELECT语句中的某个位置,但在调试一段时间之后,我发现我在开始时放入交叉引用中的值太大而且修复了它。
但我的问题是:
SQL Server如何在没有完成插入交叉引用行的情况下执行主SELECT语句?有某种延期处理吗?延迟加载表变量?
为什么地球上的“字符串或二进制数据会被截断”消息不指向它实际发生的位置?或者我做错了吗?
谢谢, 射线
修改
我认为它必须与表变量的LEFT JOIN有关,并且它的所有列都不涉及WHERE子句。 SQL Server似乎已经离开了表的准备,直到它需要(在INNER JOIN完成之后),并且当它已经将大部分结果集准备好进行SELECT时出错了。
我也注意到成功插入@cross_reference的值确实显示在返回的结果集中。虽然因为太大而无法插入的行只显示NULL。
答案 0 :(得分:1)
仅仅因为发生了错误,这不会阻止存储过程进展。您将看不到错误消息,因为默认情况下,SSMS会在查询完成处理之前显示结果网格。
在切换到错误消息之前显示10秒的结果:
RAISERROR('Error',16,1)
select top 1000 * from sys.objects so1,sys.objects so2,sys.objects so3
WAITFOR DELAY '00:00:10'
如果您希望存储过程在发生错误时提前退出,则必须提前纾困。您可以重新编写插入内容,如:
declare @cross_reference table (
context varchar(20) not null
, value1 varchar(10) not null
, value2 varchar(10) not null
)
insert into @cross_reference (context,value1,value2)
values ('map', 'from_value', 'to_value'),
('map', 'from_value', 'to_value'),
('map', 'from_value_xxxxx', 'to_value_xxxxxxx');
if @@ERROR !=0 or @@ROWCOUNT !=3 return
或者,如果您不知道行数,请将条件更改为@@ROWCOUNT = 0
(或者当然,使用TRY
/ CATCH
- 但我自己还没有编写太多使用它们的代码,所以不能只是敲出一个例子)
您当前的代码使每个插入独立 - 因此那些可以工作,执行和不能执行的插入会产生错误消息。然后它继续处理您的最终查询。因为该表是在LEFT JOIN中使用的,所以最终查询对表变量中是否存在任何行无关紧要。
答案 1 :(得分:0)
我无法准确再现您所描述的内容。关于将数据插入表var,我要说的一件事是,如果你有ANSI_WARNINGS ON,那么它应该在插入点出错。
即
SET ANSI_WARNINGS ON -- Gives the truncation error
DECLARE @T1 TABLE (value1 varchar(10) not null)
INSERT @T1 VALUES ('1234567890ABC')
SET ANSI_WARNINGS OFF -- Does not give the truncation error. "1234567890" will be inserted
DECLARE @T1 TABLE (value1 varchar(10) not null)
INSERT @T1 VALUES ('1234567890ABC')
连接是否有ANSI_WARNINGS ON或OFF?