Результаты динамического SQL во временную таблицу в хранимой процедуре SQL
Код выглядит следующим образом:
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 в общем. Но я не знаю как.
Может кто-нибудь помочь мне в этой проблеме?
9 ответов
Пытаться:
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, не беспокоясь о том, что другой процесс, вызывающий тот же sproc, будет его использовать. Это полезно, когда вы не знаете, чего ожидать от выбранной базовой таблицы при каждом ее запуске, поэтому вы не можете явно создать временную таблицу заранее. т.е. - вам нужно использовать синтаксис 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
Попробуйте код ниже для динамического создания временной таблицы из вывода хранимой процедуры с использованием T-SQL
declare @ExecutionName varchar(1000) = 'exec [spname] param1,param2 '
declare @sqlStr varchar(max) = ''
declare @tempTableDef nvarchar(max) =
(
SELECT distinct
STUFF(
(
SELECT ','+a.[name]+' '+[system_type_name]
+'
' AS [text()]
FROM sys.dm_exec_describe_first_result_set (@ExecutionName, null, 0) a
ORDER BY a.column_ordinal
FOR XML PATH ('')
), 1, 1, '') tempTableDef
FROM sys.dm_exec_describe_first_result_set (@ExecutionName, null, 0) b
)
IF ISNULL(@tempTableDef ,'') = '' RAISERROR( 'Invalid SP Configuration. At least one column is required in Select list of SP output.',16,1) ;
set @tempTableDef='CREATE TABLE #ResultDef
(
' + REPLACE(@tempTableDef,'
','') +'
)
INSERT INTO #ResultDef
' + @ExecutionName
Select @sqlStr = @tempTableDef +' Select * from #ResultDef '
exec(@sqlStr)
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
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 внутри строки, а затем выполнить эту строку? Таким образом, вы можете добавить столько столбцов, сколько захотите.