Результаты динамического 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 
INSERT INTO #TempTable
EXEC(@SelectStatement)

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

Другие вопросы по тегам