【发布时间】:2019-11-08 05:48:16
【问题描述】:
SQL Server 2012。
有一个带有 sql 语句的表,由开发人员维护。
CREATE TABLE t
(
id INT PRIMARY KEY CLUSTERED NOT NULL IDENTITY(1, 1)
, sql_statement NVARCHAR(MAX) NOT NULL
, recipient NVARCHAR(MAX) NOT NULL
);
INSERT INTO t
SELECT 'select 1 as one, 2 as two, 3 as three'
, 'some-email-address@host.com'
时不时地,一个自动化流程会启动并执行其中一个语句,检查它是否返回了任何行,如果返回,则通过电子邮件发送给它们。重要的是,该过程会根据各种条件向电子邮件添加一些额外内容,因此它不是简单的“生成并发送 csv 数据”任务(我们不能简单地使用将查询结果附加到电子邮件的内置功能) .
这个过程应该是尽可能动态的。特别是,它应该支持任何返回行的有效 SQL 语句。
从 sql_statement 列检索和处理数据的当前实现类似于:
DECLARE @sql NVARCHAR(MAX);
SELECT @sql = sql_statement
FROM dbo.t
WHERE id = 1;
DECLARE @actual_sql NVARCHAR(MAX) = N'SELECT * INTO ##t from (' + @sql + N') t;';
EXECUTE(@actual_sql)
DECLARE @msg NVARCHAR(MAX);
SELECT @msg = 'plenty of heavy-lifting here, building the email message body based on the contents of ##t and various conditions'
DROP TABLE ##t
EXECUTE msdb.dbo.sp_send_dbmail
@recipients = @recipients
, ... ...
, @body = @msg
上述解决方案的问题在于它阻止了开发人员在sql_statement 列中使用WITH 语句,因为它们会导致EXECUTE(@actual_sql) 行出现语法错误(原因很明显:你不能select from (with...) )。他们可以在FROM 块中使用子查询,但我希望他们能够使用任何返回行的 SQL 代码。
有什么解决办法吗?
【问题讨论】:
-
您是否真的将 sql 语句存储在表中以供执行?这似乎是一个非常糟糕的主意。特别是如果您不确保完全“消毒”。
-
这是一个有效的问题。这些陈述目前由一小群(
-
如果您将查询的格式强制为
N'...FROM (' + @sql + N')',则不能。 CTE 必须在语句的开头声明,而不是中间或结尾,但该 CTE 确实 的SELECT需要在结尾。您必须强制您的用户使用子查询或更改您的解决方案(根据我之前的评论,我建议后者)。 -
我的一个想法是在 @sql 变量中的最后一个“FROM”之前注入“ INTO ##t ”子句,但对于许多不起作用的场景(在使用 FROM 关键字结束查询)。另一个是教育开发人员在他们的查询中始终包含“INTO ##t”,但随着解决方案的增长,我需要能够并行运行这些东西并动态生成 ##t 表名以避免重叠。
-
专注于您的问题会对您造成伤害,因为这是xy problem
标签: sql-server sql-server-2012 dynamic-sql temp-tables