我有数百个用于商业智能的模板化ETL存储过程。他们将其运营活动记录到审计表中。缺少的一件事是记录传递给它们的参数信息。问题是从一个SP到另一个SP的参数并不总是相同的。我正在寻找一个标准的代码片段,我可以坚持到可以遍历proc的所有参数并检索传入的当前值的过程。我计划将它们一起拼接在一个字符串中以便也记录到表中。有什么想法吗?
提前感谢您的任何指示! - 蒂姆
答案 0 :(得分:2)
我正在寻找一个标准的代码片段,我可以直接进入可以遍历proc的所有参数并检索传入的当前值的过程 -
您可以使用以下查询获取sp传入的所有值
示例:
我有以下存储过程,它给我销售详细信息(仅限演示)
alter proc dbo.getsales
(
@salesid int
)
as
begin
select
* from sales where cust_id=@salesid
end
我在下面打电话给我的sp ..
exec dbo.getsales 4
现在,如果我想获得价值,我可以使用以下查询
select top 10* from sys.dm_exec_cached_plans cp
cross apply
sys.dm_exec_text_query_plan(cp.plan_handle,default,default)
where objtype='proc'
它在下面显示了编译时间值
据说,有很多事情需要考虑。我们可以使用xml方法来获取这个值
现在会发生什么,如果我再次为值2运行相同的存储过程。
<ColumnReference Column="@salesid" ParameterCompiledValue="(4)" ParameterRuntimeValue="(2)" />
这里的一个重要问题是,当我选择从ssms显示的执行计划时,会显示上述值。
但是缓存中的值是什么,让我们再次使用上面的计划缓存查询来查看它
<ColumnReference Column="@salesid" ParameterCompiledValue="(4)"/>
它仍然显示编译值,加上usecounts列为5 - `这意味着该计划已被使用了5次,并且在计划最初编译时传递的参数是4.这也意味着,运行时值不是存储在缓存计划详细信息中..
总而言之,您可以将运行时值传递给存储过程
答案 1 :(得分:0)
您不必动态检索存储过程中 的名称和参数,因为一旦创建或更改了存储过程,它就无法更改其参数,直到它被改变或重新创造。
相反,您可能在存储的proc static 中包含参数列表,但是为了不手动枚举params,您可以通过DDL触发器动态生成它。
定义一些注释标记,用于标记位置,参数应在存储过程中列出,并在适当的时候将它们添加到存储过程的主体中。触发器应该在标记之间找到标记和alter proc插入参数名称的静态列表及其值。示例如下。
<强> DDL-触发强>
create trigger StoredProc_ListParams on database
for CREATE_PROCEDURE, ALTER_PROCEDURE
as
begin
set nocount on;
if @@nestlevel > 1
return;
declare @evt xml, @sch sysname, @obj sysname, @text nvarchar(max);
set @evt = eventdata();
set @text = @evt.value('(/EVENT_INSTANCE/TSQLCommand/CommandText/text())[1]', 'nvarchar(max)');
if @text is NULL -- skip encrypted
return;
set @sch = @evt.value('(/EVENT_INSTANCE/SchemaName/text())[1]', 'sysname');
set @obj = @evt.value('(/EVENT_INSTANCE/ObjectNa1me/text())[1]', 'sysname');
declare @listParams nvarchar(max);
set @listParams = '
select name, value
from (values ' + stuff(
(select ',
' + '(' + cast(p.parameter_id as varchar(10)) + ', ''' + p.name + '''' +
', cast(' + p.name + ' as sql_variant))'
from sys.parameters p
join sys.objects o on o.object_id = p.object_id and o.type = 'P'
join sys.schemas s on s.schema_id = o.schema_id
where s.name = @sch and o.name = @obj
order by p.parameter_id
for xml path(''), type).value('text()[1]', 'nvarchar(max)'), 1, 1, '') + '
) p(num, name, value)
order by num';
declare @startMarker nvarchar(100), @endMarker nvarchar(100);
set @startMarker = '--%%LIST_PARAMS_START%%';
set @endMarker = '--%%LIST_PARAMS_END%%';
if left(@text, 6) = 'create'
set @text = stuff(@text, 1, 6, 'alter');
declare @ixStart int, @ixEnd int;
set @ixStart = nullif(charindex(@startMarker, @text), 0) + len(@startMarker);
set @ixEnd = nullif(charindex(@endMarker, @text), 0);
if @ixStart is NULL or @ixEnd is NULL
return;
set @text = stuff(@text, @ixStart, @ixEnd - @ixStart, @listParams + char(13) + char(10));
if @text is NULL
return;
exec(@text);
end
测试的存储过程的脚本:
create procedure dbo.TestProc
(
@id int,
@name varchar(20),
@someFlag bit,
@someDate datetime
)
as
begin
set nocount on;
--%%LIST_PARAMS_START%%
-- list params for me here, please
--%%LIST_PARAMS_END%%
end
以下是执行上述创建脚本后,存储过程实际在数据库中的显示方式:
alter procedure [dbo].[Test]
(
@id int,
@name varchar(20),
@someFlag bit,
@someDate datetime
)
as
begin
set nocount on;
--%%LIST_PARAMS_START%%
select name, value
from (values
(1, '@id', cast(@id as sql_variant)),
(2, '@name', cast(@name as sql_variant)),
(3, '@someFlag', cast(@someFlag as sql_variant)),
(4, '@someDate', cast(@someDate as sql_variant))
) p(num, name, value)
order by num
--%%LIST_PARAMS_END%%
end
这种方法的一个限制是它不适用于加密的存储过程。如果您希望处理表类型的参数,还需要进行一些调整。
答案 2 :(得分:0)
从SQL Server 2014开始,我们有了sys.dm_exec_input_buffer
,它是一个表值函数,其输出列event_info
给出了完整的执行语句(包括参数)。
您可以阅读完整的执行语句,然后从中解析出参数值。
例如:
这些行包含在正在执行的存储过程中
-- get the full execution statement
declare @statement nvarchar(max)
select @statement = event_info
from sys.dm_exec_input_buffer(@@spid, current_request_id())
-- parse params from the statement
declare @proc_name varchar(128) = object_name(@@procid)
declare @param_idx int = charindex(@proc_name, @statement) + len(@proc_name)
declare @param_len int = len(@statement) - @param_idx
declare @params nvarchar(max) = right(@statement, @param_len)
print @params
-- or log them...
exec log_error sysdatetime(), @proc_name, @params, error_line(), error_message()
我用它来记录捕获块中的错误。