Как сохранить результаты динамического запроса во временной таблице без создания таблицы? - PullRequest
8 голосов
/ 26 мая 2019

Мы пишем хранимую процедуру, отвечающую за получение имени хранимой процедуры, и возвращаем результат, содержащий столбцы хранимой процедуры и их типы данных. Однако мы столкнулись с проблемой выполнения динамического запроса для возврата результатов хранимой процедуры, но мы не можем сохранить его во временной таблице!

Вы можете увидеть наш запрос ниже:

  DECLARE @ProcName VARCHAR(100)='spGetOraganizationsList',
  @ParamName VARCHAR(100),@DataType VARCHAR(20),
  @Query NVARCHAR(MAX)='EXEC '+'spGetOraganizationsList '

  SELECT  PARAMETER_NAME,DATA_TYPE 
  INTO #Tmp
  FROM  information_schema.PARAMETERS
  WHERE SPECIFIC_NAME=@ProcName

  DECLARE ParamCursor CURSOR 
  FOR SELECT * FROM #Tmp
  OPEN ParamCursor
  FETCH NEXT FROM ParamCursor
  INTO @ParamName,@DataType

  WHILE @@FETCH_STATUS = 0 
  BEGIN
  SET @Query=@Query+@ParamName+'=Null,'
  FETCH NEXT FROM ParamCursor INTO @ParamName,@DataType
  END
  CLOSE ParamCursor
  DEALLOCATE ParamCursor
  DROP TABLE #Tmp

  EXEC sp_executesql @Query

Дело в том, что я не могу сохранить результаты во временной таблице, и OPENROWSET не принимает переменные.

Ответы [ 6 ]

3 голосов
/ 30 мая 2019

Я думаю, что из концепции sql он не верит в результат хранимых процедур, и поэтому мы не можем выбрать его или сохранить в таблице с помощью метода «создания в таблице запросов». Если вы не создадите таблицу и не определите ее столбцы и не будете доверять ей, а затем вставите ее результат в эту таблицу, например, возьмите следующую ситуацию

Create table test (name varchar(10),family varchar(20))


Insert into test
Exec sp-testResult

Теперь, если вы укажете неверный столбец для своей таблицы, вы получите ошибку времени выполнения запроса. На самом деле sql не предсказывает результат sp и оставляет вам право определять результат вашей хранимой процедуры.

0 голосов
/ 05 июня 2019

В C # вы можете использовать SqlDataReader или DataTable, чтобы получить результаты из хранимой процедуры, не зная заранее схемы. Если вы затем захотите записать эти данные во временную таблицу, я думаю, вы можете сделать это из C # (хотя я никогда не пытался это сделать).

0 голосов
/ 03 июня 2019

Напишите запрос выбора как вы хотите в хранимой процедуре. Вы получите результат без создания временной таблицы.

0 голосов
/ 02 июня 2019

Использовать глобальную временную таблицу и динамические OPENROWSET

  DROP TABLE ##Tmp;
  GO

  DECLARE @ProcName VARCHAR(100)='spGetOraganizationsList',
  @ParamName VARCHAR(100), @DataType VARCHAR(20),
  -- Mind to specify database and schema of the SP
  @Query NVARCHAR(MAX)=' EXEC [mydb].[dbo].spGetOraganizationsList ';
  SELECT  PARAMETER_NAME,DATA_TYPE 
  INTO #Tmp
  FROM  information_schema.PARAMETERS
  WHERE SPECIFIC_NAME=@ProcName;

  -- Build SP exec

  DECLARE ParamCursor CURSOR 
  FOR SELECT * FROM #Tmp
  OPEN ParamCursor
  FETCH NEXT FROM ParamCursor
  INTO @ParamName,@DataType

  WHILE @@FETCH_STATUS = 0 
  BEGIN
     SET @Query=@Query+@ParamName+'=Null,'
     FETCH NEXT FROM ParamCursor INTO @ParamName,@DataType
  END
  CLOSE ParamCursor
  DEALLOCATE ParamCursor
  SET @Query = left(@Query, len(@Query) - 1);

  -- Build ad hoc distributed query which creates ##Tmp from SP exec.

  SET @Query = 'SELECT * INTO ##Tmp FROM OPENROWSET(''SQLNCLI'', ''Server=localhost;Trusted_Connection=yes;'',''' + @Query + ''')';

  EXEC (@Query);

  -- Created by dynamic sql `##Tmp` is availabe in the current context. 
  SELECT *
  FROM ##Tmp;

Не забудьте сначала включить специальные распределенные запросы.

sp_configure 'Show Advanced Options', 1
GO
RECONFIGURE
GO
sp_configure 'Ad Hoc Distributed Queries', 1
GO
RECONFIGURE
GO

РЕДАКТИРОВАТЬ

Мой ответ решает только одну проблему, сохраняя результат динамического вызова proc во временной таблице.И есть еще проблемы.

Во-первых, @p=null просто не будет компилироваться, если тип @p является определяемым пользователем типом таблицы.Вам нужен вид declare @t myType; exec mySp ... ,@p=@t ....

Далее следует ошибка «не удается получить метаданные для sp, поскольку она содержит динамический запрос», которую вы прокомментировали.Похоже, вам нужно приложение, SqlClr или автономное приложение, которое сможет считывать и анализировать наборы данных, возвращаемые процессорами.

Наконец, если SP содержит условный sql, который может возвращать набор результатов различной схемы в зависимости от значений параметров, результат всех этих усилий все еще сомнителен.

0 голосов
/ 01 июня 2019

Вы, конечно, можете вставить результаты хранимой процедуры в таблицу TEMP:

CREATE PROCEDURE PurgeMe
AS
SELECT convert(int, 1) AS DaData
UNION
SELECT convert(int, 2)
GO

CREATE TABLE #Doodles  (AnInteger int)

INSERT #Doodles EXECUTE PurgeMe

SELECT * FROM #Doodles

Однако возникают вопросы по поводу ОБЛАСТИ ПРИМЕНЕНИЯ таблиц TEMP. Вы можете обнаружить, что в своей подпрограмме вызова вы не сможете увидеть таблицу TEMP, созданную в вашей подпрограмме.

Решение проблемы SCOPE заключается в следующем:

  1. Создать минимальную таблицу TEMP (скажем, с одним столбцом)
  2. Используйте ALTER TABLE для таблицы TEMP в вашей подпрограмме, чтобы согласовать ее схему ваши потребности (это может быть сложно, но это может быть сделано)
  3. Поместить данные в таблицу TEMP
  4. вернитесь из своей процедуры - вызывающая процедура теперь сможет получить доступ к временной таблица

Если это представляет интерес, я могу сделать более длинную запись с хранимой процедурой, чтобы выполнить вышеизложенное. Он был написан для облегчения динамического SQL

0 голосов
/ 30 мая 2019

Почему бы не создать представление вместо создания и удаления таблиц.

CREATE VIEW "VIEW_NAME" AS "SQL Statement";

Не связанный пример: -

CREATE VIEW V_Customer
AS SELECT First_Name, Last_Name, Country
FROM Customer;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...