2010-03-01 64 views
1

我有一些动态的sql语句在某些条件下炸弹,所以我试图调试它。它被建造像这样:在SQL Server 2008中调试长动态sql

declare @sql varchar(4000); 
... 
select @sql = '<part1>'; 
... 
select @sql = @sql + '<part2>'; 
... 
select @sql = @sql + '<part3>'; 
... 
begin 
execute(@sql); 
select @ec__errno = @@error 
    if @ec__errno != 0 
    begin 
    if @@trancount != 0 
    begin 
    rollback; 
    end 
return @ec__errno; 
end; 
... 

正如我所说的,它在一个循环的特定迭代(不要问我为什么它是这样实现的,我只是修复bug)的炸弹,我有很难在监视窗口中显示字符串的内容。我想我只能得到前255个字符。看着substring(@sql, 0, 200)结果在'substring(@sql,0,200)' could not be evaluated。请帮忙。我希望看到从0到199,从200到399等等的子串,然后把这个东西放在一起,最后调试它。

我会很感激你的指针。谢谢!

+3

我看你已经发现的原因之一动态SQL往往是一个坏主意! – HLGEM 2010-03-01 21:57:58

+0

这似乎确实如此,但可以肯定的是有些时候,刚性sql将会更不可读) - 想象一下,处理各种形状的树状东西,这些东西被塞进sql表中。 – 2010-03-01 22:00:22

+0

我没有;意思是它的可读性较差,只是在所有可能的条件下进行调试并且经常不可能进行调试。 – HLGEM 2010-03-01 22:01:49

回答

4

当被迫在存储过程中使用动态sql时,我们执行以下操作。添加一个位域的调试输入变量。如果它是0,那么exec语句将会处理,如果它是1,那么您将得到一个print语句。我建议你做一些类似于调试的东西。不是执行,而是打印SQL的结果,或者可能将SQl插入到表中,因为它似乎正在循环中发生。然后,您可以查看构建的SQL并查看错误的位置。

Declare debug bit 
set debug = 1 

... 
if debug = 1 Begin  Print @SQL End 
Else 
Begin Exec (@sql) End 

或者使用

创建一个表名为mydynamiccode_logging(用SQL列相同的长度最大SQL statment,一个rundatecolumn和任何其他列,你可能会发现有必要(我会考虑的输入变量弥补SQL statment,用户,应用程序,如果超过一个使用这段代码)

之前你都跑这样的事情EXEC statment:

insert mydynamiccode_logging (sql, rundate) 
values (@sql, getdate()) 

现在,您还可以添加调试位字段,并且只有在您将其更改为调试模式时才进行记录,或者您始终可以登录,具体取决于系统,需要多长时间才能完成,以及系统的其余部分如何受到影响。您不想通过日志记录显着降低生产速度。

+0

啊,非常酷!有没有机会检测环境?有点像#if调试... #endif,或者如果__name__ =='__main__'(Python)?我希望在执行动态sql之前添加一个打印语句,如果我在“调试”中而不是“在生产中”。有没有办法做到这一点? – 2010-03-01 22:13:09

+1

'PRINT'的问题是在生产环境中捕获它,这对于难以重现的问题至关重要。 – 2010-03-01 22:25:01

+0

我不会在生产环境中运行打印。我不会尝试在prod中进行调试。 您可以添加代码,以便始终将@ sql发送到表(在运行exec之前使用输入变量和日期时间),然后发送的所有内容都会自动记录下来,您可以通过表查找问题是一个错误,你必须看看它是如何影响执行时间的 – HLGEM 2010-03-01 23:00:11

1

做这样的事情,只会记录故障:

BEGIN TRY 

    DECLARE @LogString varchar(max) 

    --record input parameters 
    SET @LogString='@Param1='+COALESCE(''''[email protected]+'''','null') 
        [email protected]='+COALESCE(''''[email protected]+'''','null') 
        [email protected]='+COALESCE(''''+CONVERT(varchar(23),@ParamDate,121)+'''','null') 
        [email protected]='+COALESCE(''''+CONVERT(varchar(10),@Paramint)+'''','null') 

    --build @SQL_String String here 
    --repeat as necessary 
    SET @LogString=ISNULL(@LogString)+'; '+.... --every logic twist record what is going on 

    EXEC (@SQL_String) 

END TRY 
BEGIN CATCH 

    IF XACT_STATE()!=0 
    BEGIN 
     ROLLBACK TRANSACTION 
    END 

    SET @LogString=ISNULL(@LogString,'')+'; ' 
       +CASE WHEN ERROR_NUMBER()  IS NOT NULL THEN 'Msg '   +CONVERT(varchar(30), ERROR_NUMBER() ) ELSE '' END 
       +CASE WHEN ERROR_SEVERITY() IS NOT NULL THEN ', Level '  +CONVERT(varchar(30), ERROR_SEVERITY() ) ELSE '' END 
       +CASE WHEN ERROR_STATE()  IS NOT NULL THEN ', State '  +CONVERT(varchar(30), ERROR_STATE()  ) ELSE '' END 
       +CASE WHEN ERROR_PROCEDURE() IS NOT NULL THEN ', Procedure ' +      ERROR_PROCEDURE() ELSE '' END 
       +CASE WHEN ERROR_LINE()  IS NOT NULL THEN ', Line '  +CONVERT(varchar(30), ERROR_LINE()  ) ELSE '' END 
       +CASE WHEN ERROR_MESSAGE() IS NOT NULL THEN ', '   +      ERROR_MESSAGE()  ELSE '' END 

    INSERT INTO ErrorLog Values (@SQL_String) 
    INSERT INTO ErrorLog Values (@LogString) 

    --will echo back the complete original error message for the calling application 
    DECLARE @ErrorMessage nvarchar(400), @ErrorNumber int, @ErrorSeverity int, @ErrorState int, @ErrorLine int 
    SELECT @ErrorMessage = N'Error %d, Line %d, Message: '+ERROR_MESSAGE(),@ErrorNumber = ERROR_NUMBER(),@ErrorSeverity = ERROR_SEVERITY(),@ErrorState = ERROR_STATE(),@ErrorLine = ERROR_LINE() 
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorNumber,@ErrorLine) 

    RETURN 9999 

END CATCH 
+0

有趣的是,我们试图尽可能快地保持sql。这个特定修改的影响是什么? – 2010-03-01 22:14:55

+1

只有几个字符串连接,只有在INSERT失败的情况下。我无法想象它会伤害那么多。只要将它包含在正在轰炸的程序中,您将获得调试问题所需的所有信息,然后您可以对其进行注释。 – 2010-03-01 22:18:33

+0

慢速代码总是比破碎的代码快:) – BradC 2010-03-01 22:34:40