我刚刚在我的一个软件上发现了一个错误,我忘记了where子句。代码是这样的:
declare @foo bigint
declare @bar bigint
select @foo = foo, @bar=bar from tbFooBar
where (....a long list of condition goes there)
(... and an extra condition should have went there but I forgot it)
不幸的是,我忘记的where子句在非常特殊的极端情况下非常有用,并且代码已成功通过测试。
最终,查询返回了两个值而不是一个,并且生成的错误是一个要追踪的噩梦(因为它很难重现,而且这个特定的存储过程导致问题根本不明显我们发现了)
如果@ foo = foo引发异常而不是默默地从多行中分配第一个值,那么调试会容易得多。
为什么这样?我不能想到一个人实际上想要这样做而不会引起错误的情况(记住条款'不同'和'顶'是有原因的)
如果出现这种情况,有没有办法让sql server 2008引发错误?
答案 0 :(得分:8)
试试这个:
declare @d datetime
select @d = arrived from attendance;
if @@ROWCOUNT > 1 begin
RAISERROR('Was more than expected 1 row.', 16, 1)
end
答案 1 :(得分:2)
为什么这样?根据每行上分配变量 的事实,人们可以做很多事情。例如,有些人用它来执行string concatenation。
@bernd_k演示了一种导致错误的方法,假设您只分配给单个变量。目前,如果您需要分配多个变量,则无法概括该技术 - 您仍需确保查询仅返回一行
如果您担心特定查询很大/很复杂/可能稍后编辑,并且有人可能会意外导致它返回其他行,您可以引入一个新变量,并使您的选择外观像这样开始:
declare @dummy bit
select @dummy = CASE WHEN @dummy is null then 1 ELSE 10/0 END
如果返回多行,则会导致错误。
答案 2 :(得分:1)
当有多个结果时,您可以像这样制定查询而不是出错:
declare @foo bigint
select @foo = (
Select foo
from tbFoo
where (....a long list of condition goes there)
(... and an extra condition should have went there but I forgot it)
)
另一种语法的目的不是抛出错误。
修改强>
当您需要多于一列时,可以使用表变量,将结果分配给它并检查其行数并相应地工作。
答案 3 :(得分:0)
我会将值分配给表变量,并在分配后检查表是否有多个记录。事实上,我几乎从不依赖查询来返回一条记录,因为这是短视的。它可能在测试中,但一旦真实数据到达那里,它们通常不会,甚至可能不会。如果你考虑集合而不是一个记录,你将拥有更可靠的代码。