从动态@sql选择进入## temptable

时间:2019-06-26 10:03:59

标签: sql-server sql-server-2012 dynamic-sql temp-tables

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

上述解决方案的问题在于,它会阻止开发人员在WITH列中使用sql_statement语句,因为它们会导致EXECUTE(@actual_sql)行上的语法错误(原因很明显:不能select from (with...))。他们可以在FROM块中使用子查询,但是我希望他们能够使用任何返回行的SQL代码。

有什么解决方法吗?

1 个答案:

答案 0 :(得分:1)

如果您可以维护一个为每个sql_statement创建结果集架构的脚本,那么它将起作用。

DROP TABLE IF EXISTS t1
DECLARE @pre_sql NVARCHAR(MAX) = '

        CREATE TABLE [dbo].[t1] (
            [one]   [NVARCHAR](MAX) NULL
           ,[two]   [NVARCHAR](MAX) NULL
           ,[three] [NVARCHAR](MAX) NULL
        )'
EXEC sp_executesql @pre_sql

DECLARE @sql NVARCHAR(MAX) = 'with CTE AS(select 1 as one, 2 as two, 3 as three) SELECT * from CTE'

INSERT
    INTO t1 EXEC sp_executesql @sql

SELECT * FROM t1