SELECT INTO ## temptable от динамического @sql - PullRequest
0 голосов
/ 26 июня 2019

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 Ответ

1 голос
/ 27 июня 2019

Если вам удастся поддерживать скрипт, который создает схему набора результатов для каждого 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
...