Вставка результатов хранимой процедуры во временную таблицу

Как сделать SELECT * INTO [temp table] FROM [stored procedure]? Не FROM [Table] и без определения [temp table]?

Select все данные из BusinessLine в tmpBusLine отлично.

select *
into tmpBusLine
from BusinessLine

Я пытаюсь сделать то же самое, но использование stored procedure которая возвращает данные, не совсем то же самое.

select *
into tmpBusLine
from
exec getBusinessLineHistory '16 Mar 2009'

Выходное сообщение:

Msg 156, уровень 15, состояние 1, строка 2 Некорректный синтаксис рядом с ключевым словом "exec".

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

Ответы

Ответ 1

Вы можете использовать OPENROWSET для этого. Взгляни. Я также включил код sp_configure для включения специальных распределенных запросов, если он еще не включен.

CREATE PROC getBusinessLineHistory
AS
BEGIN
    SELECT * FROM sys.databases
END
GO

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

SELECT * INTO #MyTempTable FROM OPENROWSET('SQLNCLI', 'Server=(local)\SQL2008;Trusted_Connection=yes;',
     'EXEC getBusinessLineHistory')

SELECT * FROM #MyTempTable

Ответ 2

Если вы хотите сделать это без предварительного объявления временной таблицы, вы можете попытаться создать определенную пользователем функцию, а не хранимую процедуру и сделать эту пользовательскую функцию возвратой таблицы. Альтернативно, если вы хотите использовать хранимую процедуру, попробуйте что-то вроде этого:

CREATE TABLE #tmpBus
(
   COL1 INT,
   COL2 INT
)

INSERT INTO #tmpBus
Exec SpGetRecords 'Params'

Ответ 3

В SQL Server 2005 вы можете использовать INSERT INTO ... EXEC, чтобы вставить результат хранимой процедуры в таблицу. Из MSDN INSERT документация (для SQL Server 2000 фактически):

--INSERT...EXECUTE procedure example
INSERT author_sales EXECUTE get_author_sales

Ответ 4

Это ответ на слегка измененную версию вашего вопроса. Если вы можете отказаться от использования хранимой процедуры для пользовательской функции, вы можете использовать встроенную функцию, определяемую таблицей. Это, по сути, хранимая процедура (будет принимать параметры), которая возвращает таблицу в качестве результата; и поэтому будет удобно размещаться с инструкцией INTO.

Здесь хорошая быстрая статья об этом и другие пользовательские функции. Если у вас все еще есть потребность во время хранения хранимой процедуры, вы можете обернуть встроенную функцию, определенную пользователем, с помощью хранимой процедуры. Хранимая процедура просто передает параметры при вызове select * из встроенной функции, определяемой пользователем.

Так, например, у вас будет встроенная пользовательская функция, ориентированная на таблицу, чтобы получить список клиентов для определенного региона:

CREATE FUNCTION CustomersByRegion 
(  
    @RegionID int  
)
RETURNS TABLE 
AS
RETURN 
  SELECT *
  FROM customers
  WHERE RegionID = @RegionID
GO

Затем вы можете вызвать эту функцию, чтобы получить то, что ваши результаты:

SELECT * FROM CustomersbyRegion(1)

Или сделать SELECT INTO:

SELECT * INTO CustList FROM CustomersbyRegion(1)

Если вам все еще нужна хранимая процедура, то заверните функцию как таковую:

CREATE PROCEDURE uspCustomersByRegion 
(  
    @regionID int  
)
AS
BEGIN
     SELECT * FROM CustomersbyRegion(@regionID);
END
GO

Я думаю, что это самый "безрадостный" метод для получения желаемых результатов. Он использует существующие функции, поскольку они предназначались для использования без дополнительных осложнений. Вложенная встроенная функция, определяемая пользователем, в хранимой процедуре, вы получаете доступ к функциям двумя способами. Плюс! У вас есть только одна точка обслуживания для фактического кода SQL.

Было предложено использовать OPENROWSET, но это не то, для чего предназначалась функция OPENROWSET (из книги в Интернете):

Включает всю информацию о подключении, которая требуется для доступа к удаленным данным из источника данных OLE DB. Этот метод является альтернативой доступу к таблицам на связанном сервере и является разовым, специальным методом подключения и доступа к удаленным данным с использованием OLE DB. Для более частых ссылок на источники данных OLE DB вместо этого используйте связанные серверы.

Использование OPENROWSET выполнит эту работу, но при этом возникнут дополнительные накладные расходы для открытия локальных соединений и сортировки данных. Он также может быть не во всех случаях, поскольку для него требуется специальное разрешение запроса, которое создает угрозу безопасности и, следовательно, может быть нежелательным. Кроме того, подход OPENROWSET исключает использование хранимых процедур, возвращающих более одного набора результатов. Это может обеспечить объединение нескольких встроенных функций, определяемых пользователем, в одну хранимую процедуру.

Ответ 5

EXEC sp_serveroption 'YOURSERVERNAME', 'DATA ACCESS', TRUE

SELECT  *
INTO    #tmpTable
FROM    OPENQUERY(YOURSERVERNAME, 'EXEC db.schema.sproc 1')

Ответ 6

Самое простое решение:

CREATE TABLE #temp (...);

INSERT INTO #temp
EXEC [sproc];

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

SELECT * 
INTO #temp
FROM OPENROWSET('SQLNCLI', 
                'Server=localhost;Trusted_Connection=yes;', 
                'EXEC [db].[schema].[sproc]')

Ответ 7

Когда хранимая процедура возвращает много столбцов, и вы не хотите вручную "создавать" временную таблицу для хранения результата, я нашел, что самый простой способ - войти в хранимую процедуру и добавить "в", в последнем предложении select и добавьте 1 = 0 в предложение where.

Запустите хранимую процедуру один раз и вернитесь назад и удалите только что добавленный код SQL. Теперь у вас будет пустая таблица, соответствующая результату хранимой процедуры. Вы можете либо "script table as create" для временной таблицы, либо просто вставить непосредственно в эту таблицу.

Ответ 8

declare @temp table
(
    name varchar(255),
    field varchar(255),
    filename varchar(255),
    filegroup varchar(255),
    size varchar(255),
    maxsize varchar(255),
    growth varchar(255),
    usage varchar(255)
);
INSERT @temp  Exec sp_helpfile;
select * from @temp;

Ответ 9

Сохраняет ли ваша хранимая процедура только данные или их изменение? Если он используется только для извлечения, вы можете преобразовать хранимую процедуру в функцию и использовать общие выражения таблицы (CTE), не объявляя ее, как показано ниже:

with temp as (
    select * from dbo.fnFunctionName(10, 20)
)
select col1, col2 from temp

Однако все, что должно быть извлечено из CTE, должно использоваться только в одном утверждении. Вы не можете сделать with temp as ... и попытаться использовать его после нескольких строк SQL. Вы можете иметь несколько CTE в одном выражении для более сложных запросов.

Например,

with temp1020 as (
    select id from dbo.fnFunctionName(10, 20)
),
temp2030 as (
    select id from dbo.fnFunctionName(20, 30)
)
select * from temp1020 
where id not in (select id from temp2030)

Ответ 10

Если таблица результатов вашей хранимой процедуры слишком сложна, чтобы вручную ввести инструкцию "create table", и вы не можете использовать OPENQUERY или OPENROWSET, вы можете использовать sp_help для создания списка столбцов и типов данных для вы. Когда у вас есть список столбцов, это просто вопрос его форматирования в соответствии с вашими потребностями.

Шаг 1: добавьте "в #temp" к выходному запросу (например, "выберите [...] в #temp из [...]" ).

Самый простой способ - отредактировать выходной запрос в proc напрямую. если вы не можете изменить сохраненный процесс, вы можете скопировать содержимое в новое окно запроса и изменить запрос там.

Шаг 2. Запустите sp_help в таблице temp. (например, "exec tempdb..sp_help #temp" )

После создания таблицы temp запустите sp_help в таблице temp, чтобы получить список столбцов и типов данных, включая размер полей varchar.

Шаг 3: Скопируйте столбцы и типы данных в инструкцию create table

У меня есть лист Excel, который я использую для форматирования вывода sp_help в оператор "create table". Вам не нужно ничего подобного, просто скопируйте и вставьте в свой редактор SQL. Используйте имена столбцов, их размеры и типы для создания инструкции "Создать таблицу #x [...]" или "declare @x table [...]", которую вы можете использовать для INSERT результатов хранимой процедуры.

Шаг 4: Вставка во вновь созданную таблицу

Теперь у вас будет запрос, похожий на другие решения, описанные в этом потоке.

DECLARE @t TABLE 
(
   --these columns were copied from sp_help
   COL1 INT,
   COL2 INT   
)

INSERT INTO @t 
Exec spMyProc 

Этот метод также может быть использован для преобразования таблицы temp (#temp) в переменную таблицы (@temp). Хотя это может быть больше шагов, чем просто запись оператора create table самостоятельно, он предотвращает ручную ошибку, такую ​​как опечатки и несоответствия типа данных в больших процессах. Отладка опечатки может занять больше времени, чем писать запрос в первую очередь.

Ответ 11

Quassnoi поместил меня большую часть пути, но ничего не было:

**** Мне нужно было использовать параметры в хранимой процедуре. ****

И OPENQUERY не позволяет это произойти:

Итак, я нашел способ работать с системой, а также не должен делать определение таблицы таким жестким и переопределять его в другой хранимой процедуре (и, конечно, риск, что она может сломаться)!

Да, вы можете динамически создать определение таблицы, возвращенное из хранимой процедуры, используя оператор OPENQUERY с фиктивными переменными (поскольку NO RESULT SET возвращает то же количество полей и в том же положении, что и набор данных с хорошими данными).

После создания таблицы вы можете использовать хранимую процедуру exec во временной таблице в течение всего дня.


И чтобы отметить (как указано выше), вы должны включить доступ к данным,

EXEC sp_serveroption 'MYSERVERNAME', 'DATA ACCESS', TRUE

код:

declare @locCompanyId varchar(8)
declare @locDateOne datetime
declare @locDateTwo datetime

set @locDateOne = '2/11/2010'
set @locDateTwo = getdate()

--Build temporary table (based on bogus variable values)
--because we just want the table definition and
--since openquery does not allow variable definitions...
--I am going to use bogus variables to get the table defintion.

select * into #tempCoAttendanceRpt20100211
FROM OPENQUERY(DBASESERVER,
  'EXEC DATABASE.dbo.Proc_MyStoredProc 1,"2/1/2010","2/15/2010 3:00 pm"')

set @locCompanyId = '7753231'

insert into #tempCoAttendanceRpt20100211
EXEC DATABASE.dbo.Proc_MyStoredProc @locCompanyId,@locDateOne,@locDateTwo

set @locCompanyId = '9872231'

insert into #tempCoAttendanceRpt20100211
EXEC DATABASE.dbo.Proc_MyStoredProc @locCompanyId,@locDateOne,@locDateTwo

select * from #tempCoAttendanceRpt20100211
drop table #tempCoAttendanceRpt20100211

Спасибо за информацию, которая была предоставлена ​​изначально... Да, наконец, мне не нужно создавать все эти фальшивые (строгие) таблицы при использовании данных из другой хранимой процедуры или базы данных и да, вы также можете использовать параметры.

Поиск ссылочных тегов:

  • Хранимая процедура SQL 2005 в таблицу temp

  • openquery с хранимой процедурой и переменными 2005

  • openquery с переменными

  • выполнить хранимую процедуру в таблице temp

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

Замечание Bummer: это не будет работать с временными таблицами, http://www.sommarskog.se/share_data.html#OPENQUERY

Ссылка: Следующее - определить LOCALSERVER. Он может выглядеть как ключевое слово в примере, но на самом деле это только имя. Вот как вы это делаете:

sp_addlinkedserver @server = 'LOCALSERVER',  @srvproduct = '',
                   @provider = 'SQLOLEDB', @datasrc = @@servername

Чтобы создать связанный сервер, вы должны иметь разрешение ALTER ANY SERVER или быть членом любой из фиксированных ролей сервера sysadmin или setupadmin.

OPENQUERY открывает новое подключение к SQL Server. Это имеет некоторые последствия:

Процедура, которую вы вызываете с помощью OPENQUERY, не может ссылаться на временные таблицы, созданные в текущем соединении.

Новое соединение имеет свою собственную базу данных по умолчанию (определенную с помощью sp_addlinkedserver, по умолчанию - master), поэтому вся спецификация объекта должна содержать имя базы данных.

Если вы открыли транзакцию и удерживаете блокировки при вызове OPENQUERY, вызываемая процедура не может получить доступ к заблокированному. То есть, если вы не будете осторожны, вы заблокируете себя.

Подключение осуществляется не бесплатно, поэтому есть ограничение производительности.

Ответ 12

Если OPENROWSET вызывает у вас проблемы, есть другой путь, начиная с 2012 года; использовать sys.dm_exec_describe_first_result_set_for_object, как упомянуто здесь: Получить имена столбцов и типы хранимых процедур?

Сначала создайте эту хранимую процедуру, чтобы сгенерировать SQL для временной таблицы:

CREATE PROCEDURE dbo.usp_GetStoredProcTableDefinition(
    @ProcedureName  nvarchar(128),
    @TableName      nvarchar(128),
    @SQL            nvarchar(max) OUTPUT
)
AS
SET @SQL = 'CREATE TABLE ' + @tableName + ' ('

SELECT @SQL = @SQL + '['+name +'] '+ system_type_name +''  + ','
        FROM sys.dm_exec_describe_first_result_set_for_object
        (
          OBJECT_ID(@ProcedureName), 
          NULL
        );

--Remove trailing comma
SET @SQL = SUBSTRING(@SQL,0,LEN(@SQL))    
SET @SQL =  @SQL +')'

Чтобы использовать процедуру, вызовите ее следующим образом:

DECLARE     @SQL    NVARCHAR(MAX)

exec dbo.usp_GetStoredProcTableDefinition
    @ProcedureName='dbo.usp_YourProcedure',
    @TableName='##YourGlobalTempTable',@SQL = @SQL OUTPUT

INSERT INTO ##YourGlobalTempTable
EXEC    [dbo].usp_YourProcedure

select * from ##YourGlobalTempTable

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

Ответ 13

Этот хранимый proc выполняет задание:

CREATE PROCEDURE [dbo].[ExecIntoTable]
(
    @tableName          NVARCHAR(256),
    @storedProcWithParameters   NVARCHAR(MAX)
)
AS
BEGIN
    DECLARE @driver         VARCHAR(10)
    DECLARE @connectionString   NVARCHAR(600)
    DECLARE @sql            NVARCHAR(MAX)
    DECLARE @rowsetSql      NVARCHAR(MAX)

    SET @driver = '''SQLNCLI'''

    SET @connectionString = 
        '''server=' + 
            CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(256)) + 
            COALESCE('\' + CAST(SERVERPROPERTY('InstanceName') AS NVARCHAR(256)), '') + 
        ';trusted_connection=yes'''

    SET @rowsetSql = '''EXEC ' + REPLACE(@storedProcWithParameters, '''', '''''') + ''''

    SET @sql = '
SELECT
    *
INTO 
    ' + @tableName + ' 
FROM
    OPENROWSET(' + @driver + ',' + @connectionString + ',' + @rowsetSql + ')'

    EXEC (@sql)
END
GO

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

Если вы хотите, чтобы она работала с временной таблицей, вам нужно будет использовать таблицу ##GLOBAL и затем отбросить ее.

Ответ 14

Если вам посчастливилось иметь SQL 2012 или выше, вы можете использовать dm_exec_describe_first_result_set_for_object

Я только что отредактировал sql, предоставленный gotqn. Спасибо gotqn.

Это создает глобальную таблицу temp с именем, аналогичным имени процедуры. После этого временную таблицу можно использовать по мере необходимости. Просто не забудьте бросить его перед повторным выполнением.

    declare @procname nvarchar(255) = 'myProcedure',
            @sql nvarchar(max) 

    set @sql = 'create table ##' + @procname + ' ('
    begin
            select      @sql = @sql + '[' + r.name + '] ' +  r.system_type_name + ','
            from        sys.procedures AS p
            cross apply sys.dm_exec_describe_first_result_set_for_object(p.object_id, 0) AS r
            where       p.name = @procname

            set @sql = substring(@sql,1,len(@sql)-1) + ')'
            execute (@sql)
            execute('insert ##' + @procname + ' exec ' + @procname)
    end

Ответ 15

  1. Я создаю таблицу со следующей схемой и данными.
  2. Создайте хранимую процедуру.
  3. Теперь я знаю, каков результат моей процедуры, поэтому я выполняю следующий запрос.

    CREATE TABLE [dbo].[tblTestingTree](
        [Id] [int] IDENTITY(1,1) NOT NULL,
        [ParentId] [int] NULL,
        [IsLeft] [bit] NULL,
        [IsRight] [bit] NULL,
    CONSTRAINT [PK_tblTestingTree] PRIMARY KEY CLUSTERED
    (
        [Id] ASC
    ) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    SET IDENTITY_INSERT [dbo].[tblTestingTree] ON
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (1, NULL, NULL, NULL)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (2, 1, 1, NULL)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (3, 1, NULL, 1)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (4, 2, 1, NULL)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (5, 2, NULL, 1)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (6, 3, 1, NULL)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (7, 3, NULL, 1)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (8, 4, 1, NULL)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (9, 4, NULL, 1)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (10, 5, 1, NULL)
    
    SET IDENTITY_INSERT [dbo].[tblTestingTree] OFF
    

    VALUES (10, 5, 1, NULL) SET IDENTITY_INSERT [dbo]. [TblTestingTree] Вкл.

    create procedure GetDate
    as
    begin
        select Id,ParentId from tblTestingTree
    end
    
    create table tbltemp
    (
        id int,
        ParentId int
    )
    insert into tbltemp
    exec GetDate
    
    select * from tbltemp;
    

Ответ 16

Чтобы вставить первый набор записей хранимой процедуры во временную таблицу, вам необходимо знать следующее:

  1. только первый набор строк хранимой процедуры может быть вставлен во временную таблицу
  2. хранимая процедура не должна выполнять динамический оператор T-SQL (sp_executesql)
  3. сначала нужно определить структуру временной таблицы

Вышеприведенное может выглядеть как ограничение, но ИМХО оно вполне имеет смысл - если вы используете sp_executesql, вы можете один раз вернуть два столбца и один раз десять, а если у вас есть несколько наборов результатов, вы также не можете вставить их в несколько таблиц - вы можно вставить максимум в две таблицы в одном операторе T-SQL (используя предложение OUTPUT и без триггеров).

Таким образом, проблема заключается, главным образом, в том, как определить структуру временной таблицы перед выполнением оператора EXEC ... INTO ....

Первый работает с OBJECT_ID, а второй и третий работают также со специальными запросами. Я предпочитаю использовать DMV вместо sp, поскольку вы можете использовать CROSS APPLY и создавать временные определения таблиц для нескольких процедур одновременно.

SELECT p.name, r.* 
FROM sys.procedures AS p
CROSS APPLY sys.dm_exec_describe_first_result_set_for_object(p.object_id, 0) AS r;

Также обратите внимание на поле system_type_name, так как оно может быть очень полезным. В нем хранится полное определение столбца. Например:

smalldatetime
nvarchar(max)
uniqueidentifier
nvarchar(1000)
real
smalldatetime
decimal(18,2)

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

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


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

Ответ 17

Если запрос не содержит параметра, используйте OpenQuery else use OpenRowset.

Основная задача - создать схему в соответствии с хранимой процедурой и вставить ее в эту таблицу. например:.

DECLARE @abc TABLE(
                  RequisitionTypeSourceTypeID INT
                , RequisitionTypeID INT
                , RequisitionSourcingTypeID INT
                , AutoDistOverride INT
                , AllowManagerToWithdrawDistributedReq INT
                , ResumeRequired INT
                , WarnSupplierOnDNRReqSubmission  INT
                , MSPApprovalReqd INT
                , EnableMSPSupplierCounterOffer INT
                , RequireVendorToAcceptOffer INT
                , UseCertification INT
                , UseCompetency INT
                , RequireRequisitionTemplate INT
                , CreatedByID INT
                , CreatedDate DATE
                , ModifiedByID INT
                , ModifiedDate DATE
                , UseCandidateScheduledHours INT
                , WeekEndingDayOfWeekID INT
                , AllowAutoEnroll INT
                )
INSERT INTO @abc
EXEC [dbo].[usp_MySp] 726,3
SELECT * FROM @abc

Ответ 18

код

CREATE TABLE #T1
(
    col1 INT NOT NULL,
    col2 NCHAR(50) NOT NULL,
    col3 TEXT NOT NULL,
    col4 DATETIME NULL,
    col5 NCHAR(50) NULL,
    col6 CHAR(2) NULL,
    col6 NCHAR(100) NULL,
    col7 INT NULL,
    col8 NCHAR(50) NULL,
    col9 DATETIME NULL,
    col10 DATETIME NULL
)

DECLARE @Para1 int
DECLARE @Para2 varchar(32)
DECLARE @Para3 varchar(100)
DECLARE @Para4 varchar(15)
DECLARE @Para5 varchar (12)
DECLARE @Para6 varchar(1)
DECLARE @Para7 varchar(1)


SET @Para1 = 1025
SET @Para2 = N'6as54fsd56f46sd4f65sd'
SET @Para3 = N'XXXX\UserName'
SET @Para4 = N'127.0.0.1'
SET @Para5 = N'XXXXXXX'
SET @Para6 = N'X'
SET @Para7 = N'X'

INSERT INTO #T1
(
    col1,
    col2,
    col3,
    col4,
    col5,
    col6,
    col6,
    col7,
    col8,
    col9,
    col10,
)
EXEC [dbo].[usp_ProcedureName] @Para1, @Para2, @Para3, @Para4, @Para5, @Para6, @Para6

Надеюсь, это поможет. Пожалуйста, квалифицируйтесь по мере необходимости.

Ответ 19

Я нашел Передача массивов /DataTables в Хранимые процедуры, которые могут дать вам еще одну идею о том, как вы можете решить свою проблему.

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

Возможно, есть способ, которым это можно использовать с временной таблицей.

Ответ 20

Я встретил ту же проблему, и вот что я сделал для этого из предложение Павла. Основная часть здесь заключается в использовании NEWID(), чтобы избежать одновременного запуска нескольких процедур хранения/сценариев, боль для глобальной временной таблицы.

DECLARE @sql varchar(max) = '', 
@tmp_global_table varchar(255) = '##global_tmp_' + CONVERT(varchar(36), NEWID())
SET @sql = @sql + 'select * into [' + @tmp_global_table + '] from YOURTABLE'
EXEC(@sql)

EXEC('SELECT * FROM [' + @tmp_global_table + ']')

Ответ 21

Другой метод - создать тип и использовать PIPELINED, чтобы затем передать ваш объект. Однако это ограничивается знанием столбцов. Но это имеет то преимущество, что можно:

SELECT * 
FROM TABLE(CAST(f$my_functions('8028767') AS my_tab_type))

Ответ 22

После поиска я нашел способ динамически создать временную таблицу для любой хранимой процедуры без использования OPENROWSET или OPENQUERY используя общую схему определения результата хранимой процедуры, особенно если вы не являетесь администратором базы данных.

Сервер Sql имеет sp_describe_first_result_set который может предоставить вам схему любого sp_describe_first_result_set процедур. Я создал таблицу схемы из результатов этой процедуры и вручную установил все поля в NULLABLE.

declare @procname varchar(100) = 'PROCEDURENAME' -- your procedure name
declare @param varchar(max) = '''2019-06-06''' -- your parameters 
declare @execstr nvarchar(max) = N'exec ' + @procname
declare @qry nvarchar(max)

-- Schema table to store the result from sp_describe_first_result_set.
create table #d
(is_hidden  bit  NULL, column_ordinal   int  NULL, name sysname NULL, is_nullable   bit  NULL, system_type_id   int  NULL, system_type_name nvarchar(256) NULL,
max_length  smallint  NULL, precision   tinyint  NULL,  scale   tinyint  NULL,  collation_name  sysname NULL, user_type_id  int NULL, user_type_database    sysname NULL,
user_type_schema    sysname NULL,user_type_name sysname NULL,assembly_qualified_type_name   nvarchar(4000),xml_collection_id    int NULL,xml_collection_database    sysname NULL,
xml_collection_schema   sysname NULL,xml_collection_name    sysname NULL,is_xml_document    bit  NULL,is_case_sensitive bit  NULL,is_fixed_length_clr_type  bit  NULL,
source_server   sysname NULL,source_database    sysname NULL,source_schema  sysname NULL,source_table   sysname NULL,source_column  sysname NULL,is_identity_column bit NULL,
is_part_of_unique_key   bit NULL,is_updateable  bit NULL,is_computed_column bit NULL,is_sparse_column_set   bit NULL,ordinal_in_order_by_list   smallint NULL,
order_by_list_length    smallint NULL,order_by_is_descending    smallint NULL,tds_type_id   int  NULL,tds_length    int  NULL,tds_collation_id  int NULL,
tds_collation_sort_id   tinyint NULL)


-- Get result set definition of your procedure
insert into #d
EXEC sp_describe_first_result_set @exestr, NULL, 0

-- Create a query to generate and populate a global temp table from above results
select 
@qry = 'Create table ##t(' +
stuff(  
    (select ',' + name + ' '+ system_type_name + ' NULL'
    from #d d For XML Path, TYPE)
    .value(N'.[1]', N'nvarchar(max)')
, 1,1,'')
+ ')

insert into ##t 
Exec '[email protected]+' ' + @param

Exec sp_executesql @qry

-- Use below global temp table to query the data as you may
select * from ##t

-- **WARNING** Don't forget to drop the global temp table ##t.
--drop table ##t
drop table #d 

Разработано и протестировано на версии Sql Server - Microsoft SQL Server 2016 (окончательная первоначальная версия) - 13.0.1601.5 (сборка 17134 :)

Вы можете настроить схему для используемой версии сервера SQL (при необходимости).

Ответ 23

Это простой двухэтапный процесс: - создать временную таблицу - вставить во временную таблицу.

Код для выполнения такой же:

CREATE TABLE #tempTable (Column1 int, Column2 varchar(max));
INSERT INTO #tempTable 
EXEC [app].[Sproc_name]
@param1 = 1,
@param2 =2;

Ответ 24

Если вы знаете передаваемые параметры и если у вас нет доступа к make sp_configure, отредактируйте хранимую процедуру с этими параметрами, и то же самое можно сохранить в глобальной таблице ##.

Ответ 25

Ну, вам нужно создать временную таблицу, но она не должна иметь правильную схему... Я создал хранимую процедуру, которая изменяет существующую временную таблицу, чтобы она имела необходимые столбцы с правильными данными тип и порядок (удаление всех существующих столбцов, добавление новых столбцов):

GO
create procedure #TempTableForSP(@tableId int, @procedureId int)  
as   
begin  
    declare @tableName varchar(max) =  (select name  
                                        from tempdb.sys.tables 
                                        where object_id = @tableId
                                        );    
    declare @tsql nvarchar(max);    
    declare @tempId nvarchar(max) = newid();      
    set @tsql = '    
    declare @drop nvarchar(max) = (select  ''alter table tempdb.dbo.' + @tableName 
            +  ' drop column ''  + quotename(c.name) + '';''+ char(10)  
                                   from tempdb.sys.columns c   
                                   where c.object_id =  ' + 
                                         cast(@tableId as varchar(max)) + '  
                                   for xml path('''')  
                                  )    
    alter table tempdb.dbo.' + @tableName + ' add ' + QUOTENAME(@tempId) + ' int;
    exec sp_executeSQL @drop;    
    declare @add nvarchar(max) = (    
                                select ''alter table ' + @tableName 
                                      + ' add '' + name 
                                      + '' '' + system_type_name 
                           + case when d.is_nullable=1 then '' null '' else '''' end 
                                      + char(10)   
                              from sys.dm_exec_describe_first_result_set_for_object(' 
                               + cast(@procedureId as varchar(max)) + ', 0) d  
                                order by column_ordinal  
                                for xml path(''''))    

    execute sp_executeSQL  @add;    
    alter table '  + @tableName + ' drop column ' + quotename(@tempId) + '  ';      
    execute sp_executeSQL @tsql;  
end         
GO

create table #exampleTable (pk int);

declare @tableId int = object_Id('tempdb..#exampleTable')
declare @procedureId int = object_id('examplestoredProcedure')

exec #TempTableForSP @tableId, @procedureId;

insert into #exampleTable
exec examplestoredProcedure

Обратите внимание, что это не будет работать, если sys.dm_exec_describe_first_result_set_for_object не сможет определить результаты хранимой процедуры (например, если она использует временную таблицу).

Ответ 26

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

Это будет немного запутанно, но оно заимствовано у авторов, а также у Пола Уайта из DBA Stack Exchange Получить тип столбца результата хранимой процедуры. Еще раз, чтобы повторить этот подход & Пример не предназначен для процессов в многопользовательской среде. В этом случае определение таблицы задается на короткое время в глобальной временной таблице для ссылки процессом шаблона генерации кода.

Я не полностью проверил это, поэтому могут быть предупреждения, поэтому вы можете перейти по ссылке MSDN в ответе Пола Уайта. Это относится к SQL 2012 и выше.

Сначала используйте хранимую процедуру sp_describe_first_result_set, которая напоминает описание Oracle.

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

Я создал сохраненный процесс, чтобы разбить задачи, которые возвращают одно поле для выбора, чтобы создать определение временной таблицы.

CREATE OR ALTER PROCEDURE [dbo].[sp_GetTableDefinitionFromSqlBatch_DescribeFirstResultSet]
(
     @sql NVARCHAR(4000)
    ,@table_name VARCHAR(100)
    ,@TableDefinition NVARCHAR(MAX) OUTPUT
)
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @TempTableDefinition NVARCHAR(MAX)
    DECLARE @NewLine NVARCHAR(4) = CHAR(13)+CHAR(10)

    DECLARE @ResultDefinition TABLE (  --The View Definition per MSDN
      is_hidden         bit NOT NULL
    , column_ordinal    int NOT NULL
    , [name]            sysname NULL
    , is_nullable       bit NOT NULL
    , system_type_id    int NOT NULL
    , system_type_name  nvarchar(256) NULL
    , max_length        smallint NOT NULL
    , [precision]       tinyint NOT NULL
    , scale             tinyint NOT NULL
    , collation_name    sysname NULL    
    , user_type_id      int NULL
    , user_type_database    sysname NULL    
    , user_type_schema  sysname NULL
    , user_type_name    sysname NULL    
    , assembly_qualified_type_name      nvarchar(4000)  
    , xml_collection_id         int NULL
    , xml_collection_database   sysname NULL    
    , xml_collection_schema     sysname NULL    
    , xml_collection_name       sysname NULL
    , is_xml_document           bit NOT NULL            
    , is_case_sensitive         bit NOT NULL            
    , is_fixed_length_clr_type  bit NOT NULL    
    , source_server             sysname NULL            
    , source_database           sysname NULL
    , source_schema             sysname NULL
    , source_table              sysname NULL
    , source_column             sysname NULL
    , is_identity_column        bit NULL
    , is_part_of_unique_key     bit NULL
    , is_updateable             bit NULL
    , is_computed_column        bit NULL
    , is_sparse_column_set      bit NULL
    , ordinal_in_order_by_list  smallint NULL   
    , order_by_is_descending    smallint NULL   
    , order_by_list_length      smallint NULL
    , tds_type_id               int NOT NULL
    , tds_length                int NOT NULL
    , tds_collation_id          int NULL
    , tds_collation_sort_id     tinyint NULL
    )

    --Insert the description into table variable    
    INSERT @ResultDefinition
    EXEC sp_describe_first_result_set @sql

    --Now Build the string to create the table via union select statement
    ;WITH STMT AS (
        SELECT N'CREATE TABLE ' + @table_name + N' (' AS TextVal
        UNION ALL

        SELECT 
         CONCAT(
                CASE column_ordinal
                    WHEN 1 THEN '     ' ELSE '   , ' END  --Determines if comma should precede
                , QUOTENAME([name]) , '   ', system_type_name  -- Column Name and SQL TYPE
                ,CASE is_nullable 
                    WHEN 0 THEN '   NOT NULL' ELSE '   NULL' END --NULLABLE CONSTRAINT          
               ) AS TextVal
        FROM @ResultDefinition WHERE is_hidden = 0  -- May not be needed
        UNION ALL

        SELECT N');' + @NewLine
    ) 

    --Now Combine the rows to a single String
    SELECT @TempTableDefinition = COALESCE (@TempTableDefinition + @NewLine + TextVal, TextVal) FROM STMT

    SELECT @TableDefinition = @TempTableDefinition
END

Загадка заключается в том, что вам нужно использовать глобальную таблицу, но вы должны сделать ее достаточно уникальной так что вы можете создавать и создавать из него часто, не опасаясь столкновения.
В этом примере я использовал Guid (FE264BF5_9C32_438F_8462_8A5DC8DEE49E) для глобальной переменной, заменив дефисы подчеркиванием

DECLARE @sql NVARCHAR(4000) = N'SELECT @@SERVERNAME as ServerName, GETDATE() AS Today;'
DECLARE @GlobalTempTable VARCHAR(100) = N'##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable'

[email protected] can be a stored procedure name like dbo.foo without parameters

DECLARE @TableDef NVARCHAR(MAX)

DROP TABLE IF EXISTS #MyTempTable
DROP TABLE IF EXISTS ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable

EXEC [dbo].[sp_GetTableDefinitionFromSqlBatch_DescribeFirstResultSet] 
    @sql, @GlobalTempTable, @TableDef OUTPUT

--Creates the global table ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable
EXEC sp_executesql @TableDef 

--Now Call the stored procedure, SQL Statement with Params etc.
INSERT ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable
    EXEC sp_executesql @sql 

--Select the results into your undefined Temp Table from the Global Table
SELECT * 
INTO #MyTempTable
FROM ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable

SELECT * FROM #MyTempTable

DROP TABLE IF EXISTS #MyTempTable
DROP TABLE IF EXISTS ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable

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

Ответ 27

Это можно сделать в SQL Server 2014+, если SP возвращает только одну таблицу. Если кто-то найдет способ сделать это для нескольких таблиц, я хотел бы узнать об этом.

DECLARE @storeProcname NVARCHAR(MAX) = ''

SET @storeProcname = 'myStoredProc'

DECLARE @strSQL AS VARCHAR(MAX) = 'CREATE TABLE myTableName '

SELECT @strSQL = @strSQL+STUFF((
SELECT ',' +name+' ' + system_type_name 
FROM sys.dm_exec_describe_first_result_set_for_object (OBJECT_ID(@storeProcname),0)
FOR XML PATH('')
),1,1,'(') + ')'

EXEC (@strSQL)

INSERT INTO myTableName
EXEC ('myStoredProc @param1=1, @param2=2')

SELECT * FROM myTableName

DROP TABLE myTableName

Это вытаскивает определение возвращаемой таблицы из системных таблиц и использует это для построения таблицы temp для вас. Затем вы можете заполнить его из SP, как указано ранее.

Существуют также варианты этого, которые также работают с Dynamic SQL.

Ответ 28

Вы можете использовать процедуру как

create procedure sp_getBusinessLineHistory
(
@date varchar(50) /* datatype of the parameter */
)

AS

BEGIN

         select * into #tmpBusLine from BusinessLine where [email protected]
         /*or any other condition based on your requirement */

END
GO



EXEC sp_getBusinessLineHistory

@date = '16 Mar 2009' 

Это самый простой способ, который я использовал для создания и выполнения процедур в SQL.hope. Это помогает.

Ответ 29

Я бы сделал следующее

  • Создайте (преобразуйте SP в) UDF (значение таблицы UDF).

  • select * into #tmpBusLine from dbo.UDF_getBusinessLineHistory '16 Mar 2009'