Quel est le moyen le plus simple de créer une table temporaire dans SQL Server pouvant contenir le résultat d'une procédure stockée?

50

Souvent, je dois écrire quelque chose comme ce qui suit lorsque je traite avec SQL Server.

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

insert into #table_name
execute some_stored_procedure;

Mais créer une table dont la syntaxe exacte résulte d'une procédure stockée est une tâche fastidieuse. Par exemple, le résultat de sp_helppublication contient 48 colonnes! Je veux savoir s'il existe un moyen facile de le faire.

Merci.

Juste un apprenant
la source
Si vous souhaitez un format de sortie défini (et si vous êtes un administrateur de base de données, préférez un format défini!), Utilisez un fichier UDF à valeur de table. Malheureusement, ils ont des limitations sérieuses, donc ils ne sont pas toujours une option.
Jon of All Trades

Réponses:

36

Si la procédure ne fait que renvoyer un ensemble de résultats et que l' option de requêtes distribuées ad hoc est activée.

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

Ou vous pouvez configurer un serveur lié en boucle et l'utiliser à la place.

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

SELECT *
INTO  #T
FROM OPENQUERY(LOCALSERVER, 
               'SET FMTONLY OFF;
               EXEC sp_who')
Martin Smith
la source
Tu ne veux pas dire SET FMT_ONLY ON?
Andreas Ågren
@Andreas - Non, car j'ai supposé que l'idée était à la fois de créer et de peupler la table à partir de la sortie de la procédure stockée.
Martin Smith
18

Dans SQL Server 2012 et versions ultérieures, vous pouvez utiliser sys.dm_exec_describe_first_result_setlocalement, en supposant que le résultat que vous voulez obtenir est le premier résultat:

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;

Résultat:

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

Notez qu'il existe une limitation: si votre procédure stockée crée des tables #temp, la fonctionnalité de métadonnées ne fonctionne pas. C'est pourquoi je n'ai pas utilisé sp_who2. :-)

Aaron Bertrand
la source
La SELECT @sql += *expression*syntaxe est-elle documentée quelque part? faut- ORDER BYil inclure pour le rendre stable?
Ross Presser
1
@Ross oui, il a été introduit dans SQL Server 2008 et est documenté ici . ORDER BYest effectivement connu pour rendre cela moins stable . Si vous voulez que les résultats dans un ordre prévisible, utiliser FOR XML PATHou, si une nouvelle version assez de SQL Server, STRING_AGG.
Aaron Bertrand
1
Légère correction: vous êtes lié à l'arithmétique +=... la chaîne +=est documentée ici . Mais merci!
Ross Presser
@ Ross Yup, désolé.
Aaron Bertrand
3

Non. Le résultat d'une procédure stockée peut varier énormément: il n'est pas conçu pour toujours renvoyer exactement un jeu de résultats, comme un SELECT, sur un objet.

Vous devez exécuter CREATE TABLE

gbn
la source
1

Je voudrais écrire une procédure pour générer la table pour moi:

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;

Puis appelez-le avec:

EXEC p_create_table_from_procedure 'YOUR_TABLE_NAME_HERE', 'YOUR_PROCEDURE_NAME_HERE'

Remarque : remplacez 'YOUR_PROCEDURE_NAME_HERE' par le nom de votre propre procédure stockée.

Remarque : remplacez YOUR_TABLE_NAME_HERE par le nom de la table de votre choix.

Ce qui précède générera quelque chose comme ceci:

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
la source
En quoi cela diffère-t-il de la réponse de @ AaronBertrand ci-dessus?
Max Vernon