打印动态参数值
我在许多任务中使用了动态 SQL,并且不断遇到同样的问题:打印动态 T-SQL 语句中使用的变量的值。
EG:
Declare @SQL nvarchar(max), @Params nvarchar(max), @DebugMode bit, @Foobar int
select @DebugMode=1,@Foobar=364556423
set @SQL='Select @Foobar'
set @Params=N'@Foobar int'
if @DebugMode=1 print @SQL
exec sp_executeSQL @SQL,@Params
,@Foobar=@Foobar
上述代码的打印结果只是“Select @Foobar”。有什么方法可以动态打印值&正在执行的sql的变量名?或者在进行打印时,将参数替换为实际值,以便 SQL 可以重新运行?
我尝试过创建一两个函数来完成类似的事情,但涉及数据类型转换、模式匹配截断问题和非动态解决方案。我很好奇其他开发人员如何在不手动打印每个变量的情况下解决这个问题。
I've used dynamic SQL for many tasks and continuously run into the same problem: Printing values of variables used inside the Dynamic T-SQL statement.
EG:
Declare @SQL nvarchar(max), @Params nvarchar(max), @DebugMode bit, @Foobar int
select @DebugMode=1,@Foobar=364556423
set @SQL='Select @Foobar'
set @Params=N'@Foobar int'
if @DebugMode=1 print @SQL
exec sp_executeSQL @SQL,@Params
,@Foobar=@Foobar
The print results of the above code are simply "Select @Foobar". Is there any way to dynamically print the values & variable names of the sql being executed? Or when doing the print, replace parameters with their actual values so the SQL is re-runnable?
I have played with creating a function or two to accomplish something similar, but with data type conversions, pattern matching truncation issues, and non-dynamic solutions. I'm curious how other developers solve this issue without manually printing each and every variable manually.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不相信评估的语句可用,这意味着您的示例查询“Select @FooBar”永远不会在任何地方保留为“Select 364556243”
即使在探查器跟踪中,您也会看到该语句以“(@Foobar int)select @foobar”的形式命中缓存这
是有道理的,因为使用 sp_executesql 的一大好处是它能够以可靠的形式缓存语句,而无需评估变量,否则如果它替换变量并执行该语句,我们只会看到执行计划膨胀。
更新:这是朝着正确方向迈出的一步:
所有这些都可以清理并包装在一个很好的函数中,其中包含输入(@Statement、@ParamDef、@ParamVal)和将返回“准备好的”声明。我会留下一些作为练习给您,但请在您改进后回复!
使用这里的 split 函数 链接
I dont believe the evaluated statement is available, meaning your example query 'Select @FooBar' is never persisted anywhere as 'Select 364556243'
Even in a profiler trace you would see the statement hit the cache as '(@Foobar int)select @foobar'
This makes sense, since a big benefit of using sp_executesql is that it is able to cache the statement in a reliable form without variables evaluated, otherwise if it replaced the variables and executed that statement we would just see the execution plan bloat.
updated: Here's a step in right direction:
All of this could be cleaned up and wrapped in a nice function, with inputs (@Statement, @ParamDef, @ParamVal) and would return the "prepared" statement. I'll leave some of that as an exercise for you, but please post back when you improve it!
Uses split function from here link
关于大多数人如何做到这一点的主题,我只会谈论我所做的事情:
我能想到的最好方法是使用 SQL 跟踪捕获通过网络传输的查询。如果您在查询字符串中放置一些唯一的内容(作为注释),则可以很容易地在跟踪中为其应用过滤器,这样您就不会捕获超出您需要的内容。
然而,这并不全是桃子和桃子。奶油。
这仅适用于开发环境,也许 QA,具体取决于您的商店的严格程度。
如果查询需要很长时间才能运行,您可以通过在 @DebugMode = 1 的情况下向查询字符串添加“TOP 1”、“WHERE 1=2”或类似的限制子句来缓解这种情况。否则,您最终可能会等待每次都需要一段时间才能完成。
对于无法仅在调试模式下添加查询字符串的长查询,您可以在 StmtStarted 事件中捕获命令文本,然后在获得命令后立即取消查询。
如果查询是 INSERT/UPDATE/DELETE,并且 @DebugMode = 1 并且您不希望发生更改,则需要强制回滚。如果您当前没有使用显式事务,那么这样做会产生额外的开销。
如果你走这条路,你可以实现一些自动化,让生活变得更轻松。您可以为跟踪创建和启动/停止操作创建模板。您可以将结果记录到文件或表中,并以编程方式处理其中的命令文本。
On the topic of how most people do it, I will only speak to what I do:
The best way I can think of is to capture the query as it comes across the wire using a SQL Trace. If you place something unique in your query string (as a comment), it is very easy to apply a filter for it in the trace so that you don't capture more than you need.
However, it isn't all peaches & cream.
This is only suitable for a Dev environment, maybe QA, depending on how rigid your shop is.
If the query takes a long time to run, you can mitigate that by adding "TOP 1", "WHERE 1=2", or a similar limiting clause to the query string if @DebugMode = 1. Otherwise, you could end up waiting a while for it to finish each time.
For long queries where you can't add something the query string only for debug mode, you could capture the command text in a StmtStarted event, then cancel the query as soon as you have the command.
If the query is an INSERT/UPDATE/DELETE, you will need to force a rollback if @DebugMode = 1 and you don't want the change to occur. In the event you're not currently using an explicit transaction, doing that would be extra overhead.
Should you go this route, there is some automation you can achieve to make life easier. You can create a template for the trace creation and start/stop actions. You can log the results to a file or table and process the command text from there programatically.