我必须重构并记录一些foo.sql
查询,这些查询将由数据库技术支持团队共享(用于客户配置和类似的事情)。有些类型的票会定期出现,每个客户都有自己的服务器和数据库,但除此之外,架构都是相同的。
存储过程目前不是一个选项。我正在争论是否使用动态或 SQLCMD,我没有使用太多,因为我在 SQL Server 上有点新。
SQLCMD 脚本我觉得对我来说绝对“看起来”更干净,更容易阅读并根据需要对查询进行小的更改,但也强制用户启用 SQLCMD 模式。动态更困难,因为语法高亮由于使用字符串操作编写查询而丢失。
这些正在使用 Management Studio 2012 SQL 版本 2008R2 进行编辑和运行。这两种方法的优缺点是什么,或者 SQL Server 的一些“最佳实践”在一种方法或另一种方法上是什么?其中一个比另一个“更安全”吗?
动态示例:
declare @ServerName varchar(50) = 'REDACTED';
declare @DatabaseName varchar(50) = 'REDACTED';
declare @OrderIdsSeparatedByCommas varchar(max) = '597336, 595764, 594594';
declare @sql_OrderCheckQuery varchar(max) = ('
use {@DatabaseName};
select
-- stuff
from
{@ServerName}.{@DatabaseName}.[dbo].[client_orders]
as "Order"
inner join {@ServerName}.{@DatabaseName}.[dbo].[vendor_client_orders]
as "VendOrder" on "Order".o_id = "VendOrder".vco_oid
where "VendOrder".vco_oid in ({@OrderIdsSeparatedByCommas});
');
set @sql_OrderCheckQuery = replace( @sql_OrderCheckQuery, '{@ServerName}', quotename(@ServerName) );
set @sql_OrderCheckQuery = replace( @sql_OrderCheckQuery, '{@DatabaseName}', quotename(@DatabaseName) );
set @sql_OrderCheckQuery = replace( @sql_OrderCheckQuery, '{@OrderIdsSeparatedByCommas}', @OrderIdsSeparatedByCommas );
print (@sql_OrderCheckQuery); -- For debugging purposes.
execute (@sql_OrderCheckQuery);
SQLCMD 示例:
:setvar ServerName "[REDACTED]";
:setvar DatabaseName "[REDACTED]";
:setvar OrderIdsSeparatedByCommas "597336, 595764, 594594"
use $(DatabaseName)
select
--stuff
from
$(ServerName).$(DatabaseName).[dbo].[client_orders]
as "Order"
inner join $(ServerName).$(DatabaseName).[dbo].[vendor_client_orders]
as "VendOrder" on "Order".o_id = "VendOrder".vco_oid
where "VendOrder".vco_oid in ($(OrderIdsSeparatedByCommas));
只是为了解决这些问题:
从技术上讲,这两个选项都是“动态”/即席查询,在提交之前不会被解析/验证。并且两者都容易受到 SQL 注入的影响,因为它们没有参数化(尽管使用 SQLCMD 脚本,如果您从 CMD 脚本中传入一个变量,那么您确实有机会替换
'
为''
,这可能会或可能不会工作,具体取决于变量被使用)。每种方法都有优点和缺点:
如果您的支持人员没有进行临时查询而只是填写这些变量,那么他们不需要在 SSMS 中编辑这些脚本并进行不需要的更改。
我会创建 CMD 脚本来提示用户输入所需的变量值,然后使用这些值调用SQLCMD.EXE 。CMD 脚本甚至可以将执行记录到文件中,并附上时间戳和提交的变量值。
每个 SQL 脚本创建一个 CMD 脚本并放置在网络共享文件夹中。用户双击 CMD 脚本,它就可以工作了。
这是一个示例:
%OrderIDsSeparatedByCommas%
作为 SQLCMD 变量传递$(OrderIDsSeparatedByCommas)
测试 SQL 脚本(名称:FixProblemX.sql):
CMD 脚本(命名:FixProblemX.cmd):
请务必
ScriptLogPath
在脚本顶部编辑变量。此外,SQL 脚本(由SQLCMD.EXE
-i
的命令行开关指定)可能会受益于具有完全限定的路径,但并不完全确定。