Який найпростіший спосіб створити тимчасову таблицю на 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 стовпців! Я хочу знати, чи існує якийсь простий спосіб зробити це.

Дякую.


Якщо ви хочете, щоб визначений вихідний формат (і якщо ви DBA, вам слід віддати перевагу визначеному формату!), Розгляньте табличне значення 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
Незначна корекція: ви пов'язані з арифметикою +=... рядок +=документована тут . Але дякую!
Росс Пресер

@Ross yup, вибач.
Аарон Бертран

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
    );

Чим це відрізняється від відповіді @ AaronBertrand, наведеної вище?
Макс Вернон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.