Результаты динамического SQL во временную таблицу в хранимой процедуре SQL
-
20-08-2019 - |
Вопрос
Код выглядит следующим образом:
ALTER PROCEDURE dbo.pdpd_DynamicCall
@SQLString varchar(4096) = null
AS
Begin
create TABLE #T1 ( column_1 varchar(10) , column_2 varchar(100) )
insert into #T1
execute ('execute ' + @SQLString )
select * from #T1
End
Проблема в том, что я хочу вызывать разные процедуры, которые могут возвращать разные столбцы.Поэтому мне пришлось бы определить таблицу #T1 в общем виде.Но я не знаю как.
Может ли кто-нибудь помочь мне в этой проблеме?
Решение
Пытаться:
SELECT into #T1 execute ('execute ' + @SQLString )
И это очень плохо пахнет уязвимостью SQL-инъекции.
исправление (согласно комментарию @CarpeDiem):
INSERT into #T1 execute ('execute ' + @SQLString )
также опустите 'execute'
если строка sql не является процедурой
Другие советы
Вы можете определить таблицу динамически так же, как вы динамически вставляете в нее данные, но проблема заключается в области действия временных таблиц.Например, этот код:
DECLARE @sql varchar(max)
SET @sql = 'CREATE TABLE #T1 (Col1 varchar(20))'
EXEC(@sql)
INSERT INTO #T1 (Col1) VALUES ('This will not work.')
SELECT * FROM #T1
Вернутся с ошибкой «Неверное имя объекта»#T1 '. ». Это связано с тем, что временная таблица № T1 создается на «более низком уровне», чем блок выполнения кода.Чтобы исправить это, используйте глобальную временную таблицу:
DECLARE @sql varchar(max)
SET @sql = 'CREATE TABLE ##T1 (Col1 varchar(20))'
EXEC(@sql)
INSERT INTO ##T1 (Col1) VALUES ('This will work.')
SELECT * FROM ##T1
Надеюсь, это поможет, Джесси
Будьте осторожны с решением глобальной временной таблицы, поскольку это может привести к сбою, если два пользователя используют одну и ту же процедуру одновременно, поскольку глобальная временная таблица может быть видна всем пользователям...
динамически создайте глобальную временную таблицу с GUID в имени.Затем вы можете работать с ним в своем коде через dyn sql, не беспокоясь о том, что его будет использовать другой процесс, вызывающий тот же процесс.Это полезно, когда вы не знаете, чего ожидать от базовой выбранной таблицы при каждом ее запуске, поэтому вы не можете заранее явно создать временную таблицу.т.е. вам нужно использовать синтаксис SELECT * INTO
DECLARE @TmpGlobalTable varchar(255) = 'SomeText_' + convert(varchar(36),NEWID())
-- select @TmpGlobalTable
-- build query
SET @Sql =
'SELECT * INTO [##' + @TmpGlobalTable + '] FROM SomeTable'
EXEC (@Sql)
EXEC ('SELECT * FROM [##' + @TmpGlobalTable + '] ')
EXEC ('DROP TABLE [##' + @TmpGlobalTable + ']')
PRINT 'Dropped Table ' + @TmpGlobalTable
INSERT INTO #TempTable
EXEC(@SelectStatement)
DECLARE @EmpGroup INT =3 ,
@IsActive BIT=1
DECLARE @tblEmpMaster AS TABLE
(EmpCode VARCHAR(20),EmpName VARCHAR(50),EmpAddress VARCHAR(500))
INSERT INTO @tblEmpMaster EXECUTE SPGetEmpList @EmpGroup,@IsActive
SELECT * FROM @tblEmpMaster
CREATE PROCEDURE dbo.pdpd_DynamicCall
AS
DECLARE @SQLString_2 NVARCHAR(4000)
SET NOCOUNT ON
Begin
--- Create global temp table
CREATE TABLE ##T1 ( column_1 varchar(10) , column_2 varchar(100) )
SELECT @SQLString_2 = 'INSERT INTO ##T1( column_1, column_2) SELECT column_1 = "123", column_2 = "MUHAMMAD IMRON"'
SELECT @SQLString_2 = REPLACE(@SQLString_2, '"', '''')
EXEC SP_EXECUTESQL @SQLString_2
--- Test Display records
SELECT * FROM ##T1
--- Drop global temp table
IF OBJECT_ID('tempdb..##T1','u') IS NOT NULL
DROP TABLE ##T1
End
Не уверен, хорошо ли я понимаю, но, возможно, вы могли бы сформировать оператор CREATE внутри строки, а затем выполнить эту строку?Таким образом, вы можете добавить столько столбцов, сколько захотите.