web-dev-qa-db-fra.com

Insérer les résultats d'une procédure stockée dans une table temporaire

Comment faire un SELECT * INTO [temp table] FROM [stored procedure]? Pas FROM [Table] et sans définir [temp table]?

Select toutes les données de BusinessLine dans tmpBusLine fonctionnent correctement.

select *
into tmpBusLine
from BusinessLine

J'essaie la même chose, mais utiliser un stored procedure qui renvoie des données, ce n'est pas tout à fait pareil.

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

Message de sortie:

Msg 156, niveau 15, état 1, ligne 2 Syntaxe incorrecte près du mot clé "exec".

J'ai lu plusieurs exemples de création d'une table temporaire avec la même structure que la procédure stockée en sortie, ce qui fonctionne bien, mais il serait agréable de ne fournir aucune colonne.

1491
Ferdeen

Vous pouvez utiliser OPENROWSET pour cela. Regarde. J'ai également inclus le code sp_configure permettant d'activer les requêtes distribuées ad hoc, s'il n'est pas déjà activé.

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
676
Aaron Alton

Si vous souhaitez le faire sans d'abord déclarer la table temporaire, vous pouvez essayer de créer une fonction définie par l'utilisateur plutôt que procédure stockée et faire en sorte que cette fonction définie par l'utilisateur retourne une table. Alternativement, si vous souhaitez utiliser la procédure stockée, essayez l'une des solutions suivantes:

CREATE TABLE #tmpBus
(
   COL1 INT,
   COL2 INT
)

INSERT INTO #tmpBus
Exec SpGetRecords 'Params'
580
Gavin

Dans SQL Server 2005, vous pouvez utiliser INSERT INTO ... EXEC pour insérer le résultat d'une procédure stockée dans une table. De documentation INSERT de MSDN) (pour SQL Server 2000, en fait):

--INSERT...EXECUTE procedure example
INSERT author_sales EXECUTE get_author_sales
282
Matt Hamilton

Ceci est une réponse à une version légèrement modifiée de votre question. Si vous pouvez abandonner l'utilisation d'une procédure stockée pour une fonction définie par l'utilisateur, vous pouvez utiliser une fonction définie par l'utilisateur et intégrée à une table. Il s’agit essentiellement d’une procédure stockée (prenant des paramètres) qui renvoie une table en tant qu’ensemble de résultats; et donc va bien se placer avec une déclaration INTO.

Voici un bon article rapide sur celui-ci et d'autres fonctions définies par l'utilisateur. Si vous avez toujours besoin d'une procédure stockée, vous pouvez envelopper la fonction utilisateur définie dans la table inline avec une procédure stockée. La procédure stockée transmet uniquement les paramètres lorsqu'elle appelle select * à partir de la fonction définie par l'utilisateur et intégrée à la table.

Ainsi, par exemple, vous auriez une fonction définie par l'utilisateur et intégrée à une table pour obtenir une liste de clients pour une région particulière:

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

Vous pouvez ensuite appeler cette fonction pour obtenir ce que vos résultats sont tels:

SELECT * FROM CustomersbyRegion(1)

Ou pour faire un SELECT INTO:

SELECT * INTO CustList FROM CustomersbyRegion(1)

Si vous avez toujours besoin d'une procédure stockée, enveloppez la fonction en tant que telle:

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

Je pense que c'est la méthode la plus simple pour obtenir les résultats souhaités. Il utilise les fonctionnalités existantes, car elles étaient destinées à être utilisées sans complications supplémentaires. En imbriquant la fonction définie par l'utilisateur inline dans la procédure stockée, vous avez accès à la fonctionnalité de deux manières. Plus! Vous n'avez qu'un seul point de maintenance pour le code SQL réel.

L'utilisation d'OPENROWSET a été suggérée, mais ce n'est pas ce pour quoi la fonction OPENROWSET était destinée à être utilisée (dans la documentation en ligne):

Inclut toutes les informations de connexion requises pour accéder aux données distantes à partir d'une source de données OLE DB. Cette méthode constitue une alternative à l'accès aux tables d'un serveur lié et constitue une méthode ponctuelle et unique de connexion et d'accès à des données distantes à l'aide de la base de données OLE. Pour des références plus fréquentes aux sources de données OLE DB, utilisez plutôt des serveurs liés.

Utiliser OPENROWSET permettra d’effectuer le travail correctement, mais cela entraînera des frais généraux supplémentaires pour l’ouverture de connexions locales et le tri des données. Il se peut également que cette option ne soit pas une option dans tous les cas, car elle nécessite une autorisation de requête ad hoc, ce qui pose un risque pour la sécurité et peut donc ne pas être souhaitée. En outre, l'approche OPENROWSET empêchera l'utilisation de procédures stockées renvoyant plusieurs ensembles de résultats. Pour ce faire, il est possible de regrouper plusieurs fonctions définies par l'utilisateur en tant que valeurs de table inline dans une seule procédure stockée.

186
Christian Loris
EXEC sp_serveroption 'YOURSERVERNAME', 'DATA ACCESS', TRUE

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

La solution la plus simple:

CREATE TABLE #temp (...);

INSERT INTO #temp
EXEC [sproc];

Si vous ne connaissez pas le schéma, vous pouvez procéder comme suit. Veuillez noter que cette méthode comporte de graves risques pour la sécurité.

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

Lorsque la procédure stockée renvoie un grand nombre de colonnes et que vous ne souhaitez pas "créer" manuellement une table temporaire destinée à contenir le résultat, j'ai trouvé le moyen le plus simple consiste à entrer dans la procédure stockée et à ajouter une clause "into" à la fin du processus. dernière instruction de sélection et ajouter 1 = 0 à la clause where.

Exécutez la procédure stockée une fois et revenez en arrière et supprimez le code SQL que vous venez d'ajouter. Maintenant, vous aurez une table vide correspondant au résultat de la procédure stockée. Vous pouvez soit "table de script en tant que créer" pour une table temporaire ou simplement insérer directement dans cette table.

98
dotjoe
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;
65
nitin

Si la table des résultats de votre procédure stockée est trop compliquée pour taper manuellement l'instruction "create table" et que vous ne pouvez pas utiliser OPENQUERY OR OPENROWSET, vous pouvez utiliser sp_help pour générer la liste des colonnes et types de données pour vous. Une fois que vous avez la liste des colonnes, il vous suffit de la formater pour répondre à vos besoins.

Étape 1: Ajouter "en #temp" à la requête en sortie (par exemple, "sélectionner [...] dans #temp à partir de [...]").

Le moyen le plus simple consiste à modifier directement la requête de sortie dans le proc. si vous ne pouvez pas modifier le proc stocké, vous pouvez copier le contenu dans une nouvelle fenêtre de requête et y modifier la requête.

Étape 2: exécutez sp_help sur la table temporaire. (Par exemple, "exec tempdb..sp_help #temp")

Après avoir créé la table temporaire, exécutez sp_help sur la table temporaire pour obtenir une liste des colonnes et des types de données, y compris la taille des champs varchar.

Étape 3: Copiez les types et les colonnes de données dans une instruction create table

J'ai une feuille Excel que j'utilise pour formater la sortie de sp_help en une instruction "create table". Vous n'avez besoin de rien d'extraordinaire, il vous suffit de copier et coller dans votre éditeur SQL. Utilisez les noms, les tailles et les types de colonne pour construire une instruction "Create table #x [...]" ou "declare @x table [...]" que vous pouvez utiliser pour INSÉRER les résultats de la procédure stockée.

Étape 4: Insérer dans la table nouvellement créée

Vous avez maintenant une requête qui ressemble aux autres solutions décrites dans ce fil de discussion.

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

INSERT INTO @t 
Exec spMyProc 

Cette technique peut également être utilisée pour convertir une table temporaire (#temp) en une variable de table (@temp). Bien que cela puisse être plus qu'une simple écriture de l'instruction create table, cela évite les erreurs manuelles telles que les fautes de frappe et les types de données non concordants dans les processus volumineux. Le débogage d'une coquille peut prendre plus de temps que l'écriture de la requête.

46
FistOfFury

Votre procédure stockée récupère-t-elle uniquement les données ou les modifie-t-elle également? S'il n'est utilisé que pour la récupération, vous pouvez convertir la procédure stockée en une fonction et utiliser les expressions de table communes (CTE) sans avoir à la déclarer, comme suit:

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

Cependant, tout ce qui doit être extrait du CTE ne devrait être utilisé que dans une seule déclaration. Vous ne pouvez pas faire un with temp as ... et essayer de l'utiliser après quelques lignes de SQL. Vous pouvez avoir plusieurs CTE dans une instruction pour des requêtes plus complexes.

Par exemple,

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)
46
Rashmi Pandit

Quassnoi m'a mis la plupart du temps là-bas, mais une chose manquait:

**** J'avais besoin d'utiliser des paramètres dans la procédure stockée. ****

Et OPENQUERY ne permet pas que cela se produise:

J'ai donc trouvé un moyen de faire fonctionner le système sans avoir à rendre la définition de la table aussi rigide et à la redéfinir dans une autre procédure stockée (et bien sûr, risquer une rupture)!

Oui, vous pouvez créer de manière dynamique la définition de table renvoyée à partir de la procédure stockée à l’aide de l’instruction OPENQUERY avec de fausses variables (tant que le NO RESULT SET renvoie le même nombre de champs et le même nombre de champs). même position qu’un ensemble de données contenant de bonnes données).

Une fois la table créée, vous pouvez utiliser la procédure stockée exec dans la table temporaire toute la journée.


Et pour noter (comme indiqué ci-dessus), vous devez activer l'accès aux données,

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

Code:

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

Merci pour les informations fournies à l'origine ... Oui, enfin, je n'ai pas à créer toutes ces fausses] (strictes) définitions de table lors de l'utilisation de données d'une autre procédure stockée ou base de données, et oui vous pouvez aussi utiliser des paramètres.

Rechercher des tags de référence:

  • Procédure stockée SQL 2005 dans la table temporaire

  • openquery avec procédure stockée et variables 2005

  • openquery avec des variables

  • exécuter la procédure stockée dans la table temporaire

Mise à jour: cela ne fonctionnera pas avec les tables temporaires, donc j'ai dû créer manuellement la table temporaire.

Avis Bummer: cela ne fonctionnera pas avec tables temporaires, http://www.sommarskog.se/share_data.html#OPENQUERY

Référence: La prochaine étape consiste à définir LOCALSERVER. Cela peut ressembler à un mot-clé dans l'exemple, mais ce n'est en fait qu'un nom. Voici comment vous le faites:

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

Pour créer un serveur lié, vous devez disposer de l'autorisation ALTER ANY SERVER ou être membre de l'un des rôles de serveur fixes sysadmin ou setupadmin.

OPENQUERY ouvre une nouvelle connexion à SQL Server. Cela a des implications:

La procédure que vous appelez avec OPENQUERY ne peut pas faire référence à des tables temporaires créées dans la connexion en cours.

La nouvelle connexion a sa propre base de données par défaut (définie avec sp_addlinkedserver, default est master), de sorte que toute spécification d'objet doit inclure un nom de base de données.

Si vous avez une transaction ouverte et maintenez des verrous lorsque vous appelez OPENQUERY, la procédure appelée ne peut pas accéder à ce que vous verrouillez. Autrement dit, si vous ne faites pas attention, vous allez vous bloquer.

La connexion n'est pas gratuite, il y a donc une pénalité de performance.

30

Si OPENROWSET vous cause des problèmes, il existe un autre moyen à partir de 2012; utilisez sys.dm_exec_describe_first_result_set_for_object, comme indiqué ici: Récupérez les noms de colonne et les types d'une procédure stockée?

Tout d’abord, créez cette procédure stockée pour générer le code SQL du serveur temporaire.

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 +')'

Pour utiliser la procédure, appelez-la de la manière suivante:

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

Notez que j'utilise une table temporaire globale. En effet, l'utilisation de EXEC pour exécuter le SQL dynamique crée sa propre session. Une table temporaire ordinaire serait donc hors de portée pour tout code ultérieur. Si une table temporaire globale pose un problème, vous pouvez utiliser une table temporaire ordinaire, mais tout code SQL ultérieur doit être dynamique, c'est-à-dire exécuté également. par la déclaration EXEC.

27
StuartQ

Ce processus stocké fait le travail:

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

C'est un léger remaniement de ceci: Insérer les résultats de la procédure stockée dans la table pour que cela fonctionne réellement.

Si vous voulez qu'elle fonctionne avec une table temporaire, vous devrez utiliser une table ##GLOBAL et la supprimer ensuite.

22
briantyler

Si vous avez la chance d'avoir SQL 2012 ou supérieur, vous pouvez utiliser dm_exec_describe_first_result_set_for_object

Je viens de modifier le SQL fourni par gotqn. Merci gotqn.

Cela crée une table temporaire globale avec le même nom que le nom de la procédure. La table temporaire peut être utilisée ultérieurement si nécessaire. Juste n'oubliez pas de le laisser tomber avant de le ré-exécuter.

    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
20
Sandeep Gaadhe
  1. Je crée une table avec le schéma et les données suivants.
  2. Créez une procédure stockée.
  3. Maintenant que je connais le résultat de ma procédure, j'effectue la requête suivante.

    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
    

    VALEURS (10, 5, 1, NULL) SET IDENTITY_INSERT [dbo]. [TblTestingTree] On

    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;
    
17
Devansh

Pour insérer le premier jeu d'enregistrements d'une procédure stockée dans une table temporaire, vous devez connaître les éléments suivants:

  1. seul le premier ensemble de lignes de la procédure stockée peut être inséré dans une table temporaire
  2. la procédure stockée ne doit pas exécuter l'instruction T-SQL dynamique (sp_executesql)
  3. vous devez d'abord définir la structure de la table temporaire

Ce qui précède peut sembler une limitation, mais à mon humble avis, cela a du sens: si vous utilisez sp_executesql, vous pouvez renvoyer une ou deux colonnes et une fois, et si vous avez plusieurs ensembles de résultats, vous ne pouvez pas les insérer dans plusieurs tables. - vous pouvez insérer un maximum de deux tables dans une seule instruction T-SQL (en utilisant la clause OUTPUT et aucun déclencheur).

Le problème consiste donc principalement à définir la structure de la table temporaire avant d'exécuter l'instruction EXEC ... INTO ....

Le premier fonctionne avec OBJECT_ID tandis que le second et le troisième fonctionnent également avec les requêtes Ad-hoc. Je préfère utiliser le DMV au lieu du sp, car vous pouvez utiliser CROSS APPLY et créer les définitions de table temporaire pour plusieurs procédures à la fois.

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;

Faites également attention au champ system_type_name car il peut être très utile. Il stocke la définition complète de la colonne. Par exemple:

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

et vous pouvez l'utiliser directement dans la plupart des cas pour créer la définition de la table.

Donc, je pense que dans la plupart des cas (si la procédure stockée répond à certains critères), vous pouvez facilement créer des instructions dynamiques pour résoudre ces problèmes (créer la table temporaire, insérer le résultat de la procédure stockée, faire ce dont vous avez besoin avec les données) .


Notez que les objets ci-dessus ne parviennent pas à définir les données du premier ensemble de résultats dans certains cas , comme lorsque des instructions T-SQL dynamiques sont exécutées ou que des tables temporaires sont utilisées dans la procédure stockée.

16
gotqn

Si la requête ne contient pas de paramètre, utilisez OpenQuery sinon utilisez OpenRowset.

La chose de base serait de créer un schéma selon la procédure stockée et de l'insérer dans cette table. par exemple.:

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
15
ProblemSolver

Code

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

J'espère que ça aide. S'il vous plaît qualifier comme approprié.

12
SoftwareARM

J'ai trouvé passer des tableaux/tables de données dans des procédures stockées, ce qui pourrait vous donner une autre idée de la façon dont vous pourriez résoudre votre problème.

Le lien suggère d'utiliser un paramètre de type Image à transmettre à la procédure stockée. Ensuite, dans la procédure stockée, l'image est transformée en une variable de table contenant les données d'origine.

Peut-être y a-t-il un moyen de l'utiliser avec une table temporaire.

11
kevchadders

J'ai rencontré le même problème et voici ce que j'ai fait pour cela de suggestion de Paul . La partie principale est d’utiliser NEWID() pour éviter que plusieurs utilisateurs n’exécutent les procédures/scripts de la boutique en même temps, la douleur pour la table temporaire globale.

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 + ']')
10
zhongxiao37

Une autre méthode consiste à créer un type et à utiliser PIPELINED pour ensuite renvoyer votre objet. Cela se limite toutefois à connaître les colonnes. Mais il a l'avantage de pouvoir faire:

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

Après des recherches, j'ai trouvé un moyen de créer une table temporaire de manière dynamique pour toute procédure stockée sans utiliser OPENROWSET ou OPENQUERY à l'aide d'un schéma générique de la définition du résultat de la procédure stockée, en particulier lorsque vous n'êtes pas administrateur de base de données.

Le serveur SQL a un processus intégré sp_describe_first_result_set qui peut vous fournir un schéma de résultats de procédures. J'ai créé une table de schéma à partir des résultats de cette procédure et défini manuellement le champ sur 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 '+@procname+' ' + @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 

Développé et testé sur la version SQL Server - Microsoft SQL Server 2016 - RTM - 13.0.1601.5 (Build 17134 :)

Vous pouvez modifier le schéma pour la version de votre serveur SQL que vous utilisez (si nécessaire).

6
vendettamit

Si vous connaissez les paramètres en cours de transmission et si vous n'avez pas accès à make sp_configure, éditez la procédure stockée à l'aide de ces paramètres et vous pourrez la stocker dans une table globale ##.

4
lakshmivisalij

C'est un processus simple en 2 étapes: - créer une table temporaire - Insérer dans la table temporaire.

Code pour effectuer la même chose:

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

Eh bien, vous devez créer une table temporaire, mais elle ne doit pas nécessairement disposer du bon schéma .... J'ai créé une procédure stockée qui modifie une table temporaire existante afin qu'elle contienne les colonnes requises avec les bonnes données. type et ordre (suppression de toutes les colonnes existantes, ajout de nouvelles colonnes):

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

Note Cela ne fonctionnera pas si sys.dm_exec_describe_first_result_set_for_object ne peut pas déterminer les résultats de la procédure stockée (par exemple, s'il utilise une table temporaire).

1
jmoreno

Cela peut être fait dans SQL Server 2014+ à condition que SP ne renvoie qu'une seule table. Si quelqu'un trouve un moyen de le faire pour plusieurs tables, j'aimerais bien le savoir.

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

Cela extrait la définition de la table renvoyée des tables système et l'utilise pour construire la table temporaire à votre place. Vous pouvez ensuite le renseigner à partir du SP comme indiqué précédemment.

Il existe également des variantes qui fonctionnent avec Dynamic SQL.

0
Matthew Baker