どのようにSELECT * INTO [temp table] FROM [stored procedure]
をするのですか? FROM [Table]
ではなく[temp table]
を定義せずに?
Select
BusinessLine
からtmpBusLine
までのすべてのデータは正常に機能します。
select *
into tmpBusLine
from BusinessLine
私は同じことを試みていますが、データを返すstored procedure
を使うことは全く同じではありません。
select *
into tmpBusLine
from
exec getBusinessLineHistory '16 Mar 2009'
出力メッセージ:
メッセージ156、レベル15、状態1、行2キーワード 'exec'の近くに誤った構文があります。
出力ストアドプロシージャと同じ構造を持つ一時テーブルを作成するいくつかの例を読みましたが、これは問題なく動作しますが、列を指定しないのがいいでしょう。
これには _ openrowset _ を使用できます。見てください。アドホック分散クエリを有効にするためのsp_configureコードも含まれています(まだ有効になっていない場合)。
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
最初に一時テーブルを宣言せずにそれを実行したい場合は、 ストアドプロシージャ ではなくユーザー定義関数を作成し、そのユーザー定義関数にテーブルを返させることができます。あるいは、ストアドプロシージャを使用したい場合は、次のようにしてください。
CREATE TABLE #tmpBus
(
COL1 INT,
COL2 INT
)
INSERT INTO #tmpBus
Exec SpGetRecords 'Params'
SQL Server 2005では、INSERT INTO ... EXEC
を使用してストアドプロシージャの結果をテーブルに挿入できます。 MSDNのINSERT
ドキュメント から(実際にはSQL Server 2000用):
--INSERT...EXECUTE procedure example
INSERT author_sales EXECUTE get_author_sales
これはあなたの質問を少し修正したものに対する答えです。ユーザ定義関数に対するストアドプロシージャの使用を中止できる場合は、インラインテーブル値のユーザ定義関数を使用できます。これは基本的には結果セットとしてテーブルを返すストアドプロシージャです(パラメータを取ります)。したがって、INTOステートメントを使用してうまく配置できます。
これと/その他のユーザ定義関数についてのよい 簡単な記事 があります。それでもストアドプロシージャが必要な場合は、インラインテーブル値のユーザー定義関数をストアドプロシージャでラップすることができます。ストアード・プロシージャーは、インライン表値ユーザー定義関数からselect *を呼び出すときにパラメーターを渡すだけです。
たとえば、特定の地域の顧客のリストを取得するためのインラインテーブル値ユーザー定義関数があります。
CREATE FUNCTION CustomersByRegion
(
@RegionID int
)
RETURNS TABLE
AS
RETURN
SELECT *
FROM customers
WHERE RegionID = @RegionID
GO
その後、この関数を呼び出して、結果がそのようなものであることを確認できます。
SELECT * FROM CustomersbyRegion(1)
またはSELECT INTOを実行するには:
SELECT * INTO CustList FROM CustomersbyRegion(1)
それでもストアドプロシージャが必要な場合は、関数を次のようにラップします。
CREATE PROCEDURE uspCustomersByRegion
(
@regionID int
)
AS
BEGIN
SELECT * FROM CustomersbyRegion(@regionID);
END
GO
私はこれが望ましい結果を得るための最も「ハックの少ない」方法だと思います。それらは追加の複雑さなしで使用されるように意図されていたのでそれは既存の機能を使用します。ストアドプロシージャでインラインテーブル値ユーザー定義関数をネストすることで、2つの方法で機能にアクセスできます。プラス!実際のSQLコードのメンテナンスポイントは1つだけです。
OPENROWSETの使用が提案されていますが、これはOPENROWSET関数が(Books Onlineから)使用されることを意図したものではありません。
OLE DBデータソースからリモートデータにアクセスするために必要なすべての接続情報を含みます。この方法は、リンクサーバーのテーブルにアクセスする代わりの方法で、OLE DBを使用してリモートデータに接続してアクセスする一時的なアドホック方法です。 OLE DBデータソースへのより頻繁な参照については、代わりにリンクサーバーを使用してください。
OPENROWSETを使用すると、仕事は完了しますが、ローカル接続を開いてデータを整列化するための追加のオーバーヘッドが発生します。セキュリティリスクをもたらすアドホッククエリの許可が必要であり、したがって望ましくない可能性があるため、これはすべての場合に選択肢とは限りません。また、OPENROWSETアプローチでは、複数の結果セットを返すストアドプロシージャを使用できなくなります。単一のストアドプロシージャで複数のインラインテーブル値ユーザー定義関数をラップすると、これを実現できます。
EXEC sp_serveroption 'YOURSERVERNAME', 'DATA ACCESS', TRUE
SELECT *
INTO #tmpTable
FROM OPENQUERY(YOURSERVERNAME, 'EXEC db.schema.sproc 1')
最も簡単な解決策:
CREATE TABLE #temp (...); INSERT INTO #temp EXEC [sproc];
スキーマがわからない場合は、次の操作を実行できます。 この方法には深刻なセキュリティリスクがあることに注意してください。
SELECT *
INTO #temp
FROM OPENROWSET('SQLNCLI',
'Server=localhost;Trusted_Connection=yes;',
'EXEC [db].[schema].[sproc]')
ストアドプロシージャが多数の列を返し、結果を保持するために一時テーブルを手動で "作成"したくない場合は、ストアドプロシージャに入って "into"句を最後のselect文を実行し、where句に1 = 0を追加します。
ストアドプロシージャを1回実行して戻り、追加したSQLコードを削除します。これで、ストアドプロシージャの結果に一致する空のテーブルができました。一時テーブル用に「create as as create」テーブルを作成することも、単にそのテーブルに直接挿入することもできます。
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;
ストアドプロシージャの結果テーブルが複雑すぎて "create table"ステートメントを手動で入力できず、OPENQUERY OR OPENROWSETを使用できない場合は、sp_helpを使用して列のリストを生成しあなたのためのデータ型。列のリストを取得したら、それはニーズに合わせてフォーマットすることだけです。
ステップ1:出力クエリに "into #temp"を追加します(例: "select [...]から#temp from [...]"まで)。
最も簡単な方法はprocの出力クエリを直接編集することです。保存したプロシージャを変更できない場合は、その内容を新しいクエリウィンドウにコピーして、そこでクエリを変更できます。
ステップ2:一時テーブルに対してsp_helpを実行します。 (例: "exec tempdb..sp_help #temp")
一時テーブルを作成したら、一時テーブルに対してsp_helpを実行して、varcharフィールドのサイズを含む列とデータ型のリストを取得します。
ステップ3:データ列と型をcreate tableステートメントにコピーする
Sp_helpの出力を "create table"ステートメントにフォーマットするために使用するExcelシートがあります。気の利いたものは必要ありません。単にコピーしてSQLエディタに貼り付けてください。列名、サイズ、および型を使用して、ストアドプロシージャの結果をINSERTするために使用できる "Create table #x [...]"または "declare @x table [...]"ステートメントを作成します。
ステップ4:新しく作成したテーブルに挿入する
これで、このスレッドで説明されている他のソリューションと似たクエリができます。
DECLARE @t TABLE
(
--these columns were copied from sp_help
COL1 INT,
COL2 INT
)
INSERT INTO @t
Exec spMyProc
この手法は、一時テーブル(#temp
)をテーブル変数(@temp
)に変換するためにも使用できます。これはcreate table
ステートメントを自分で書くことよりも多くのステップになるかもしれませんが、大規模プロセスでのタイプミスやデータ型の不一致などの手動エラーを防ぎます。タイプミスをデバッグすることは、最初にクエリを書くよりも時間がかかることがあります。
ストアドプロシージャはデータを取得するだけなのか、それとも変更するだけなのか。検索専用として使用する場合は、ストアドプロシージャを関数に変換し、宣言することなく次のように共通テーブル式(CTE)を使用できます。
with temp as (
select * from dbo.fnFunctionName(10, 20)
)
select col1, col2 from temp
ただし、CTEから取得する必要があるものはすべて1つのステートメントでのみ使用してください。 with temp as ...
を実行して、数行のSQLの後に使用することはできません。より複雑な照会のために、1つのステートメントに複数のCTEを含めることができます。
例えば、
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はほとんどの方法で私をそこに置きましたが、一つ欠けていました:
そのため、システムを動作させる方法を見つけました。また、テーブル定義をそれほど厳格にせず、別のストアドプロシージャ内で再定義する必要もありません(もちろん、壊れる可能性があります)。
はい。NO RESULT SETが同じ数のフィールドを返し、良好なデータを持つデータセットと同じ位置)。
テーブルが作成されたら、execストアドプロシージャを1日中一時テーブルに使用できます。
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
元々提供されていた情報をありがとう...はい、最後に、データを使用するときにこれらすべての偽の(厳密な)テーブル定義を作成する必要はありません別のストアドプロシージャまたはデータベース、およびyesパラメーターも使用できます。
検索参照タグ:
一時テーブルへのSQL 2005ストアドプロシージャ
ストアドプロシージャと変数2005を使用したopenquery
変数を使用したopenquery
一時テーブルにストアドプロシージャを実行する
更新:これは一時テーブルでは機能しないため、手動で一時テーブルを作成する必要がありました。
バマー通知:これは一時テーブルでは動作しません、 http://www.sommarskog.se/share_data.html#OPENQUERY
参照:次に、LOCALSERVERを定義します。例ではキーワードのように見えますが、実際には名前にすぎません。これがあなたのやり方です:
sp_addlinkedserver @server = 'LOCALSERVER', @srvproduct = '',
@provider = 'SQLOLEDB', @datasrc = @@servername
リンクサーバーを作成するには、権限ALTER ANY SERVERを持っているか、固定サーバーロールsysadminまたはsetupadminのメンバーである必要があります。
OPENQUERYは、SQL Serverへの新しい接続を開きます。これにはいくつかの意味があります。
OPENQUERYで呼び出すプロシージャは、現在の接続で作成された一時テーブルを参照できません。
新しい接続には独自のデフォルトデータベース(sp_addlinkedserverで定義され、デフォルトはmaster)があるため、すべてのオブジェクト指定にデータベース名を含める必要があります。
オープントランザクションがあり、OPENQUERYを呼び出すときにロックを保持している場合、呼び出されたプロシージャはロックしたものにアクセスできません。つまり、注意しないと自分をブロックしてしまいます。
接続は無料ではないため、パフォーマンスが低下します。
OPENROWSETが問題を引き起こしている場合、2012年以降は別の方法があります。ここで説明したように、sys.dm_exec_describe_first_result_set_for_objectを使用します。 列名とストアドプロシージャの型を取得しますか?
まず、このストアドプロシージャを作成して、一時的なSQLを生成します。
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 +')'
プロシージャを使用するには、次の方法で呼び出します。
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
グローバル一時テーブルを使用していることに注意してください。これは、EXECを使用して動的SQLを実行すると独自のセッションが作成されるため、通常の一時テーブルは後続のコードの範囲外になるためです。グローバル一時テーブルに問題がある場合、canは通常の一時テーブルを使用できますが、後続のSQLは動的である必要があります。 EXECステートメントによって。
このストアドプロシージャは仕事をします:
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
これは少しやり直したものです。 ストアドプロシージャの結果をtable に挿入して、実際に動作するようにします。
一時テーブルで機能させたい場合は、##GLOBAL
テーブルを使用して、後で削除する必要があります。
あなたがSQL 2012以上を持っているのに十分幸運なら、あなたはdm_exec_describe_first_result_set_for_object
を使うことができます
Gotqnが提供するSQLを編集したところです。ありがとうございました。
これにより、プロシージャ名と同じ名前のグローバル一時表が作成されます。一時テーブルは後で必要に応じて使用できます。再実行する前に削除するのを忘れないでください。
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
これで、自分のプロシージャの結果が何であるかがわかったので、次のクエリを実行しています。
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
VALUES(10、5、1、NULL)SET IDENTITY_INSERT [dbo]。[tblTestingTree]オン
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;
ストアドプロシージャの最初のレコードセットを一時テーブルに挿入するには、次のことを知っておく必要があります。
sp_executesql
)上記は制限に見えるかもしれませんが、私たちは完全に理にかなっています - もしあなたがsp_executesql
を使っているなら2回と10回を返すことができます。 1つのT-SQLステートメント内の2つのテーブルで最大(OUTPUT
節を使用し、トリガーは使用しない)。
したがって、問題は主にEXEC ... INTO ...
ステートメントを実行する前に一時テーブル構造を定義する方法です。
1つ目はOBJECT_ID
で動作し、2つ目と3つ目はアドホッククエリでも動作します。 CROSS APPLY
を使用して同時に複数のプロシージャー用の一時表定義を作成できるので、spの代わりにDMVを使用することをお勧めします。
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;
また、system_type_name
フィールドは非常に便利なので注意してください。列の完全な定義を格納します。例えば:
smalldatetime
nvarchar(max)
uniqueidentifier
nvarchar(1000)
real
smalldatetime
decimal(18,2)
ほとんどの場合、テーブル定義を作成するために直接使用できます。
そのため、ほとんどの場合(ストアドプロシージャが特定の条件を満たす場合)、そのような問題を解決するための動的ステートメントを簡単に作成できると思います(一時テーブルを作成し、その中にストアドプロシージャの結果を挿入し、データを使って必要な処理を行います)。 。
動的T-SQLステートメントが実行されたり、一時テーブルがストアード・プロシージャーで使用されたりする場合のように、上記のオブジェクトは ケース 内の最初の結果セット・データを定義できません。
クエリにパラメータが含まれていない場合はOpenQuery
を、それ以外の場合はOpenRowset
を使用してください。
基本的なことは、ストアドプロシージャに従ってスキーマを作成し、そのテーブルに挿入することです。例えば。:
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
コード
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
これが役に立つことを願っています。適切な資格を得てください。
私は配列/データテーブルをストアドプロシージャに渡すを見つけました。これはあなたがあなたの問題を解決する方法について別の考えを与えるかもしれません。
リンクは、ストアドプロシージャに渡すために Image typeパラメータを使用することを提案します。その後、ストアドプロシージャで、イメージは元のデータを含むテーブル変数に変換されます。
一時テーブルでこれを使用できる方法があるかもしれません。
私は同じ問題に遭遇しました、そして、これは私が ポールの提案から - 私がしたことです 。ここでの主な部分は、複数のユーザーが同時にストアドプロシージャ/スクリプトを実行しないようにするためにNEWID()
を使用することです。これは、グローバル一時表の問題です。
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 + ']')
もう1つの方法は、型を作成し、PIPELINEDを使ってオブジェクトを返すことです。ただし、これは列を知ることに限定されています。しかし、それにはできるという利点があります。
SELECT *
FROM TABLE(CAST(f$my_functions('8028767') AS my_tab_type))
周りを検索した後、特にデータベース管理者でない場合、ストアドプロシージャの結果定義の汎用スキーマを使用して、OPENROWSET
またはOPENQUERY
を使用せずに、ストアドプロシージャの一時テーブルを動的に作成する方法を見つけました。
SQLサーバーには、任意のプロシージャの結果セットのスキーマを提供できるbuit-in proc sp_describe_first_result_set
があります。この手順の結果からスキーマテーブルを作成し、すべてのフィールドを手動で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
Sql Serverバージョンで開発およびテスト済み-Microsoft SQL Server 2016(RTM)-13.0.1601.5(Build 17134 :)
使用しているSQLサーバーのバージョンに合わせてスキーマを調整できます(必要な場合)。
渡されているパラメータがわかっていて、sp_configureを作成するためのアクセス権がない場合は、これらのパラメータを使用してストアドプロシージャを編集し、同じ手順を##グローバルテーブルに格納できます。
SPが1つのテーブルのみを返す場合、これはSQL Server 2014以降で実行できます。誰かが複数のテーブルでこれを行う方法を見つけた場合、私はそれについて知りたいです。
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
これにより、返されたテーブルの定義がシステムテーブルから取得され、それを使用して一時テーブルが作成されます。その後、前述のようにSPからデータを入力できます。
動的SQLでも機能するこのバリアントもあります。
それは簡単な2ステップのプロセスです: - 一時テーブルを作成します - 一時テーブルに挿入します。
同じことを実行するためのコード:
CREATE TABLE #tempTable (Column1 int, Column2 varchar(max));
INSERT INTO #tempTable
EXEC [app].[Sproc_name]
@param1 = 1,
@param2 =2;
まあ、あなたは一時テーブルを作成する必要がありますが、それは正しいスキーマを持っている必要はありません....私はそれが正しいデータで必要な列を持つように既存の一時テーブルを修正するストアドプロシージャを作成しました型と順序(既存のすべての列を削除し、新しい列を追加する):
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
注 sys.dm_exec_describe_first_result_set_for_objectがストアドプロシージャの結果を判断できない場合(たとえば一時テーブルを使用している場合など)、これは機能しません。