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.
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
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'
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
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.
EXEC sp_serveroption 'YOURSERVERNAME', 'DATA ACCESS', TRUE
SELECT *
INTO #tmpTable
FROM OPENQUERY(YOURSERVERNAME, 'EXEC db.schema.sproc 1')
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]')
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.
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;
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.
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)
Quassnoi m'a mis la plupart du temps là-bas, mais une chose manquait:
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.
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
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.
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.
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.
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
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;
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:
sp_executesql
)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.
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
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é.
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.
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 + ']')
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))
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).
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 ##.
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;
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).
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.