SQL中print、sp_helptext的限制与扩展
在SQL中,使用动态SQL是很常见的。有些复杂的计算,或是存储过程,代码很长,中间可能有多次执行SQL语句。而调试拼串的SQL语句却是件痛苦的事,很难看出来运行的语句是什么。所以我会经常使用print这个命令把运行前的语句打印到屏幕上,然后复制出来到另一个窗口进行调试、修改,这样就比较方便了。但是这个print命令有一些限制,在单字节符集下,最大只能打印打印8000个字符的长度,而在双字节字符集是4000个。
以下存储过程可以打印完整的信息,不受长度的限制。代码如下:
IFOBJECT_ID(N'sp_print_all')ISNOTNULL BEGIN DROPPROCEDUREsp_print_all END GO CREATEPROCEDUREsp_print_all(@dynamic_sqlNVARCHAR(MAX)) AS DECLARE@startINT DECLARE@lenINT SET@start=1 SET@len=4000 WHILE(@start<LEN(@dynamic_sql)) BEGIN PRINTSUBSTRING(@dynamic_sql,@start,@len) SET@start=@start+@len END PRINTSUBSTRING(@dynamic_sql,@start,@len) GO
code-1
还有一个存储sp_helptext,可以查询存储过程,函数等代码,使用起来也比较方便,但也有长度的限制,而且打印出来的格式跟源代码的格式有些对应不上。写了一个自定义存储过程来代替,代码如下:
IFOBJECT_ID(N'sp_helptext_user')ISNOTNULL BEGIN DROPPROCEDUREsp_helptext_user END GO CREATEPROCEDUREsp_helptext_user(@obj_nameNVARCHAR(200)='') AS SETNOCOUNTON; DECLARE@textNVARCHAR(MAX) ,@iINT ,@text2NVARCHAR(MAX) ,@db_nameSYSNAME ,@obj_idBIGINT SET@db_name=PARSENAME(@obj_name,3) IF@db_nameISNULL SET@db_name=DB_NAME() ELSE IF@db_name<>DB_NAME() BEGIN RAISERROR(15250,-1,-1) RETURN(1) END SET@obj_id=OBJECT_ID(@obj_name) IF@obj_idISNULL BEGIN RAISERROR(15009,-1,-1,@obj_name,@db_name) RETURN(1) END SELECT@text=[definition] FROMsys.all_sql_modules WHERE[object_id]=@obj_id WHILELEN(@text)>2000 BEGIN SET@i=CHARINDEX(CHAR(13),@text,2000) SET@text2=LEFT(@text,@i) SET@text=SUBSTRING(@text,@i+2,LEN(@text)) PRINT@text2 END PRINT@text SETNOCOUNTOFF; GO
code-2
当然,查看源代码有多种方法,可以在SSMS上操作等,看个人习惯或方便操作了。
详解sp_helptext
显示规则、默认值、未加密的存储过程、用户定义函数、触发器或视图的文本。
语法
sp_helptext[@objname=]'name'
参数
[@objname=]'name'
对象的名称,将显示该对象的定义信息。对象必须在当前数据库中。name的数据类型为nvarchar(776),没有默认值。
返回代码值
0(成功)或1(失败)
注释
sp_helptext在多个行中显示用来创建对象的文本,其中每行有Transact-SQL定义的255个字符。这些定义只驻留在当前数据库的syscomments表的文本中。
权限
执行权限默认授予public角色。
示例
下面的示例显示employee_insupd触发器的文本,该触发器在数据库pubs中。
USEpubs EXECsp_helptext'employee_insupd'