Какой самый простой способ создать временную таблицу в SQL Server, которая может содержать результат хранимой процедуры?

50

Много раз мне нужно написать что-то вроде следующего при работе с SQL Server.

create table #table_name
(
    column1 int,
    column2 varchar(200)
    ...
)

insert into #table_name
execute some_stored_procedure;

Но создать таблицу с точным синтаксисом в результате хранимой процедуры - утомительная задача. Например, результат sp_helppublication имеет 48 столбцов! Я хочу знать, есть ли простой способ сделать это.

Благодарю.

Просто ученик
источник
Если вам нужен определенный формат вывода (и если вы администратор базы данных, вам следует выбрать определенный формат!), Рассмотрите UDF с табличным значением. К сожалению, у них есть некоторые серьезные ограничения, поэтому они не всегда доступны.
Джон на все руки

Ответы:

36

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

SELECT * 
INTO #T 
FROM OPENROWSET('SQLNCLI', 
                'Server=(local)\MSSQL2008;Trusted_Connection=yes;',
                 'SET FMTONLY OFF;EXEC sp_who')

Или вы можете установить сервер с обратной связью и использовать его вместо этого.

EXEC sp_addlinkedserver @server = 'LOCALSERVER',  @srvproduct = '',
                        @provider = 'SQLNCLI', @datasrc = @@servername

SELECT *
INTO  #T
FROM OPENQUERY(LOCALSERVER, 
               'SET FMTONLY OFF;
               EXEC sp_who')
Мартин Смит
источник
Ты имеешь в виду SET FMT_ONLY ON?
Андреас Агрен
@Andreas - Нет, потому что я предполагал, что идея состоит в том, чтобы как создать, так и заполнить таблицу из вывода хранимой процедуры.
Мартин Смит
18

В SQL Server 2012 и более sys.dm_exec_describe_first_result_setпоздних версиях вы можете использовать локально, предполагая, что набор результатов, к которому вы стремитесь, является первым результатом:

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += ',' + CHAR(13) + CHAR(10) + CHAR(9)
    + name + ' ' + system_type_name
    FROM sys.dm_exec_describe_first_result_set('sp_who', NULL, 1);

SELECT @sql = N'CREATE TABLE #f
(' + STUFF(@sql, 1, 1, N'') + '
);';

PRINT @sql;

Результат:

CREATE TABLE #f
(
    spid smallint,
    ecid smallint,
    status nchar(30),
    loginame nvarchar(128),
    hostname nchar(128),
    blk char(5),
    dbname nvarchar(128),
    cmd nchar(16),
    request_id int
);

Обратите внимание, что есть ограничение: если ваша хранимая процедура создает таблицы #temp, функциональность метаданных не работает. Вот почему я не использовал sp_who2. :-)

Аарон Бертран
источник
Является ли SELECT @sql += *expression*документирован синтаксис где - нибудь? должен ORDER BYбыть включен, чтобы сделать его стабильным?
Росс Прессер
1
@ Ross да, он был представлен в SQL Server 2008 и задокументирован здесь . ORDER BYна самом деле известно, чтобы сделать это менее стабильным . Если вы хотите , чтобы результаты в предсказуемом порядке, использовать FOR XML PATHили, если на достаточно новой версии SQL Server, STRING_AGG.
Аарон Бертран
1
Небольшая коррекция: вы связались с арифметикой +=... строка +=задокументирована здесь . Но спасибо!
Росс Прессер
@ Росс, извини.
Аарон Бертран
3

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

Вы должны выполнить CREATE TABLE

ГБН
источник
1

Я бы написал процедуру для генерации таблицы для меня:

CREATE PROCEDURE [dbo].[p_create_table_from_procedure]
    @TABLE_NAME AS NVARCHAR(MAX),
    @PROCEDURE_NAME AS NVARCHAR(MAX)

As
    DECLARE @CREATE_TABLE_QUERY NVARCHAR(MAX) = N'';


    SELECT 
        @CREATE_TABLE_QUERY += ', ' + name + ' ' + UPPER(system_type_name) + CHAR(13) + CHAR(10) + CHAR(9)

    FROM 
        sys.dm_exec_describe_first_result_set(@procedure_name, NULL, 1);


    SELECT 
        @CREATE_TABLE_QUERY = N'CREATE TABLE ' + @table_name + '(' + CHAR(13) + CHAR(10) + CHAR(9) + STUFF(@CREATE_TABLE_QUERY, 1, 1, N'') + ');';

    PRINT @CREATE_TABLE_QUERY;

Затем позвоните с помощью:

EXEC p_create_table_from_procedure 'YOUR_TABLE_NAME_HERE', 'YOUR_PROCEDURE_NAME_HERE'

Примечание . Замените YOUR_PROCEDURE_NAME_HERE именем своей собственной хранимой процедуры.

Примечание . Замените YOUR_TABLE_NAME_HERE именем таблицы по вашему выбору.

Выше будет генерировать что-то вроде этого:

CREATE TABLE YOUR_TABLE_NAME_HERE(
     WeekName VARCHAR(40)
    , Line Name VARCHAR(50)
    , TheDate DATETIME
    , ReceivedAll INT
    , Answered INT
    , Abandoned INT
    , Call Length INT
    , WaitTimeAnswer INT
    , WaitTimeAbandon INT
    , PeriodName VARCHAR(10)
    , Week SMALLINT
    , Period SMALLINT
    , Year SMALLINT
    , WeekInPeriod SMALLINT
    , NumWeeksInPeriod SMALLINT
    , WeekendDate DATETIME
    , CRCOperative VARCHAR(100)
    , CallType VARCHAR(20)
    , Charge Time INT
    , SourceNumber VARCHAR(80)
    , DestinationNumber VARCHAR(80)
    , CallStart DATETIME
    , Out of Hours VARCHAR(12)
    , IsWorkingDay BIT
    );
Knickerless-Noggins
источник
Чем это отличается от ответа @ AaronBertrand выше?
Макс Вернон