在用户定义函数中如何输出PRINT?

82
基本上,我想在用户定义的函数中使用PRINT语句来帮助我调试。
然而,我收到以下错误信息:
“在函数中使用具有副作用或时间相关性运算符的'PRINT' 无效。”
这样做不行吗?
有没有方法可以帮助我调试用户定义的函数?

3
要执行这个操作的实际方法,请参见:https://dev59.com/smTWa4cB1Zd3GeqPASrt#10721985 - KM.
2
无论您要测试什么值-只需声明一个稍后将删除的变量,并将其作为数据集的一部分返回。这只是另一个选项。 - Alexey Shevelyov
8个回答

61

提示:产生错误。

declare @Day int, @Config_Node varchar(50)

    set @Config_Node = 'value to trace'

    set @Day = @Config_Node

您将收到此消息:

在将varchar值“value to trace”转换为int数据类型时,转换失败。


1
如果您想追踪的值是一个整数,该怎么办? - Roel
1
真的是个很好的技巧..我一直有这个问题!!如果要跟踪一个int值,你可以尝试使用Roel的方法: select @day = 'int value# ' + convert(varchar(10), @int_value_to_trace) - dhiman
2
聪明的笑声。当你不给我们一个方便的“正确”方式时,我们会发明一个方便的“错误”方式。 - tsilb

40

抱歉,SQL Server中的用户定义函数非常有限,因为其需要是确定性的。据我所知,没有任何绕过此要求的方法。

您尝试使用Visual Studio调试SQL代码了吗?


33
我通过临时重写我的函数来解决这个问题,代码如下:
IF OBJECT_ID ('[dbo].[fx_dosomething]', 'TF') IS NOT NULL
  drop function [dbo].[fx_dosomething];
GO

create FUNCTION dbo.fx_dosomething ( @x numeric )
returns @t table (debug varchar(100), x2 numeric)
as
begin
 declare @debug varchar(100)
 set @debug = 'printme';

 declare @x2 numeric
 set @x2 = 0.123456;

 insert into @t values (@debug, @x2)
 return 
end
go

select * from fx_dosomething(0.1)

1
我喜欢这种方法,非常有创意。只需将调试输出作为返回表中的另一列返回即可 :-). - Mister_Tom

28

过去我倾向于分两个阶段处理我的函数。第一阶段是将它们视为相当正常的SQL查询,并确保我得到了正确的结果。在我确认它按预期执行后,我才会将其转换为UDF。


15

使用扩展存储过程xp_cmdshell运行一个Shell命令。我用它来将输出打印到文件中:

exec xp_cmdshell 'echo "mytextoutput" >> c:\debuginfo.txt'

如果debuginfo.txt文件不存在,则此操作将创建该文件。然后,它会将文本“mytextoutput”(不带引号)添加到文件中。对该函数的任何调用都将写入一行额外的内容。

您可能需要先启用此db-server属性(默认为禁用),我意识到这可能不符合dba在生产环境中的喜好。


2
不要忘记先运行:EXEC sp_configure 'xp_cmdshell',1 GORECONFIGURE GO - Jan
不要忘记先运行:EXEC sp_configure 'show advanced options', 1 GO RECONFIGURE GO - Irawan Soetomo
要将日期时间和注释打印到文件中,您可以执行以下操作: EXEC xp_cmdshell 'echo %DATE%_%TIME% Processing something >> d:\Log\debuginfo.log'这将在文件中创建一个输出,看起来像: Thu 02/21/2019_18:53:10.18 Processing something - Jana Sattainathan

4
不可以。
你可以从存储过程中调用一个函数,并且可以调试存储过程(这会进入函数)。

or make it a stored procedure - access_granted

1
在我看来,每当我想要打印或调试一个函数时,我会将其内容复制为普通的SQL脚本运行。例如:
我的函数:
create or alter function func_do_something_with_string(@input nvarchar(max)) returns nvarchar(max)
as begin
   -- some function logic content
   declare @result nvarchar(max)
   set @result = substring(@input , 1, 10)
   -- or do something else

   return @result
end

然后我只需将其复制并在函数外部运行以进行调试

    declare @input nvarchar(max) = 'Some string'      

    -- some function logic content
    declare @result nvarchar(max)
    set @result = substring(@input , 1, 10)
    -- this line is added to check while debugging
    print @result 
    
    -- or do something else
    -- print the final result
    print @result

当您使用递归时,这种方法不起作用。 - Pawel Wujczyk

0
你可以尝试返回你想要检查的变量。 例如,我有这个函数:
--Contencates seperate date and time strings and converts to a datetime. Date should be in format 25.03.2012. Time as 9:18:25.
ALTER FUNCTION [dbo].[ufn_GetDateTime] (@date nvarchar(11), @time nvarchar(11))
RETURNS datetime
AS
BEGIN

        --select dbo.ufn_GetDateTime('25.03.2012.', '9:18:25')

    declare @datetime datetime

    declare @day_part nvarchar(3)
    declare @month_part nvarchar(3)
    declare @year_part nvarchar(5)

    declare @point_ix int

    set @point_ix = charindex('.', @date)
    set @day_part = substring(@date, 0, @point_ix)

    set @date = substring(@date, @point_ix, len(@date) - @point_ix)
    set @point_ix = charindex('.', @date)

    set @month_part = substring(@date, 0, @point_ix)

    set @date = substring(@date, @point_ix, len(@date) - @point_ix)
    set @point_ix = charindex('.', @date)

    set @year_part = substring(@date, 0, @point_ix)

    set @datetime = @month_part + @day_part  + @year_part + ' ' + @time

    return @datetime
END

当我运行它时,出现以下错误: Msg 241, Level 16, State 1, Line 1 Conversion failed when converting date and/or time from character string.
啊!该怎么办呢?
ALTER FUNCTION [dbo].[ufn_GetDateTime] (@date nvarchar(11), @time nvarchar(11))
RETURNS nvarchar(22)
AS
BEGIN

        --select dbo.ufn_GetDateTime('25.03.2012.', '9:18:25')

    declare @day_part nvarchar(3)
    declare @point_ix int

    set @point_ix = charindex('.', @date)
    set @day_part = substring(@date, 0, @point_ix)

    return @day_part
END

我得到了'25'。所以,我差了一个,于是我进行了更改...

set @day_part = substring(@date, 0, @point_ix + 1)

太好了!现在它可以工作了 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接