ストアドプロシージャの結果を一時テーブルに挿入する


1579

どうすればよいSELECT * INTO [temp table] FROM [stored procedure]ですか?ないFROM [Table]と定義しませんか[temp table]

SelectからBusinessLineへのすべてのデータはtmpBusLine問題なく機能します。

select *
into tmpBusLine
from BusinessLine

私は同じことを試みてstored procedureいますが、データを返すa を使用することはまったく同じではありません。

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

出力メッセージ:

メッセージ156、レベル15、状態1、行2キーワード「exec」付近の構文が正しくありません。

出力ストアドプロシージャと同じ構造の一時テーブルを作成するいくつかの例を読みましたが、これは問題なく機能しますが、列を指定しない方がいいでしょう。


22
SELECT * INTO [TABLE NAME]を使用すると、元のテーブルからコピーされた列がわかります。これは、ストアドプロシージャに対して同じことをする場合に必要なことです。
フェルディーン2009年


7
「select * into tmpBusLine」が永続的なテーブルを作成することを指摘したいだけです。おそらく「select * into #tmpBusLine」が必要です。元の投稿者はすでにこれを見つけたと思いますが、「select into temp table」の現在のトップ結果であるこの投稿を見つける他の人を助けるかもしれません
ktam33

2
これが解決されたかどうかはわかりませんが、エラーが発生するのはfromキーワードが原因です。
ウェスパルマー

9
MicrosoftはSELECT * INTO FROM EXECを追加する必要があります!お願いします!
kjmerf

回答:


704

これには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

28
これが正しい方法です。OPENROWSETは、ストアドプロシージャの結果をテーブル式として扱う唯一の方法です。
Rob Farley、

37
これは、テーブルに挿入するだけでは少し面倒です。行うための多くの設定。また、「メッセージ7357、レベル16、状態2、行1でオブジェクト "EXEC GetPartyAnalysisData 146"を処理できません。リンクサーバー "(null)"のOLE DBプロバイダー "SQLNCLI"は、オブジェクトに列がないか、現在のユーザーにそのオブジェクトに対する権限がありません。」したがって、リンクサーバーを設定する必要があります...
フェルディーン09

10
リンクサーバーは必要ありませんが、接続文字列を正しく取得する必要があります。また、データベース名とspの所有者を含むストアドプロシージャへの完全なパスを指定します。
MartW 2009

18
ええええええ!同じサーバーへの参照?不快な。間違いなく、一時テーブルを手動で作成するよりもハックの方が多い
Tim Abell

23
これはハックであり、背中が壁に当たらない限り回避する必要があることに同意します。spを関数に変更することは、おそらくより良い角度です。私見では。
2013

624

最初に一時テーブルを宣言せずにそれを実行したい場合は、ストアドプロシージャではなくユーザー定義関数を作成して、そのユーザー定義関数がテーブルを返すようにすることができます。あるいは、ストアドプロシージャを使用する場合は、次のようなことを試してください。

CREATE TABLE #tmpBus
(
   COL1 INT,
   COL2 INT
)

INSERT INTO #tmpBus
Exec SpGetRecords 'Params'

171
スキーマを明示的に宣言せずに生成することがポイントだったと思います。
クレイグ

5
これと上記の@Aaron Altonのソリューションの違いを知りたいです。これははるかに単純に見えますが、他の影響についてはよくわかりません。
funkymushroom

11
これは機能しますが、SpGetRecordsストアドプロシージャに列を追加した場合、これは爆発します。
Brady Holt

15
呼び出しスタックごとに1つのINSERT INTO EXECしか取得できません。SpGetRecordsおよびそれが呼び出すその他のプロシージャは、独自のコードでこの戦略を使用しない場合があります。これは、SpGetRecordsのメンテナを驚かせる可能性があります。
Matt Stephenson、

33
これは質問にまったく答えません、そしてなぜそれがそれほど賛成されているのかわかりませんか?OPは「[temp table]を定義せずに」と明示的に述べ、最初の行にはcreate temp tableステートメントがあります。
NickG

296

SQL Server 2005ではINSERT INTO ... EXEC、ストアドプロシージャの結果をテーブルに挿入するために使用できます。MSDNのINSERTドキュメントから(実際にはSQL Server 2000の場合):

--INSERT...EXECUTE procedure example
INSERT author_sales EXECUTE get_author_sales

122
これには、authors_salesを事前に定義する必要があります。私はこれを回避しようとしています。ありがとう。
フェルディーン2009年

5
私は同じくらい考えました。tmpテーブルへのオンザフライでの挿入は非常に便利ですが、ストアドプロシージャから返されるデータセット構造を知る必要がある場合はあまり役に立ちません。助けてくれてありがとう。
フェルディーン2009年


4
次のように同じスキーマを使用するには、コピーを行うことができます。realTable(からTEMPTABLEに選択トップ0 * stackoverflow.com/a/9206463/73794
でもミエン

@EvenMienあなたのコメントを見たとき、私は一瞬興奮しました...しかし、悲しいことに、これは、プロシージャの結果が実際に実際のテーブルをミラーリングしている場合にのみ機能します:(
BVernon

193

これはあなたの質問の少し修正されたバージョンへの回答です。ユーザー定義関数のストアドプロシージャの使用を中止できる場合は、インラインテーブル値のユーザー定義関数を使用できます。これは基本的に、結果セットとしてテーブルを返すストアドプロシージャ(パラメーターを受け取ります)です。したがって、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アプローチでは、複数の結果セットを返すストアドプロシージャを使用できなくなります。複数のインラインテーブル値ユーザー定義関数を1つのストアドプロシージャでラップすると、これを実現できます。


4
+1テーブル値関数は適切なソリューションです。小さな欠点に注意する必要があります。テーブル値関数は追加のデータベースオブジェクトであり、その権限を付与する必要がある場合があります。
spencer7593 2010

2
ソリューションが大好きです。私が遭遇した1つのマイナーな問題は、私のテーブルがストアドプロシージャでそれを持っている可能性があるので、どこに順序を置くことができないことです。おお、それを整理します
mrwaim

5
もう1つの問題-「関数内から一時テーブルにアクセスできない」
mrwaim

7
元の質問は、spの結果を使用して一時テーブルをどのように作成するかです。これは良いパターンですが、この質問には対応していません
集約

16
総計、私の答えの最初の行は「これはあなたの質問のわずかに変更されたバージョンに対する答えです」と述べています あなたのコメントは冗長です。
クリスチャンロリス2013年

131
EXEC sp_serveroption 'YOURSERVERNAME', 'DATA ACCESS', TRUE

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

2
「メッセージ208、レベル16、状態1、行1無効なオブジェクト名「tmpBusLine」を取得します(おそらく前もって定義されていないため)
Ferdeen

1
@Ferds:申し訳ありませんが、最初はリクエストを理解できませんでした。別のソリューションで更新されました。
Quassnoi 09

26
素晴らしいソリューション。注意点の1つとして、サーバーで「データアクセス」を有効にする必要があります。EXECsp_serveroption 'TheServerName'、 'DATA ACCESS'、TRUE
jcollum

8
また、サーバーへのリモートアクセスを許可する必要があります。これにはセキュリティ上の問題があります。
BraveNewMath 2013年

7
ターゲットストアドプロシージャが一時テーブルを使用している場合、これは機能しません
Sal

125

最も簡単な解決策:

CREATE TABLE #temp (...);

INSERT INTO #temp
EXEC [sproc];

スキーマがわからない場合は、次の操作を実行できます。この方法には重大なセキュリティ上のリスクがあることに注意してください。

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

返された結果セットの列がわからない場合は??? つまり、列が異なる場合があります。どのように結果を一時テーブルに挿入するのですか?
SHEKHAR SHETE 16

OPENQUERYを使用することもできますが、セキュリティ上の欠陥があるため推奨されません。
Tigerjz32 2016

1
「返された結果セットの列がわからない場合」は、ロジックで使用できません。データが何かわからない場合、どのように使用しますか?
Adriaan Davel

@AdriaanDavel私はあなたが常にデータを知っているべきだとあなたに同意します(ベストプラクティス)。その場合、OPENROWSETを使用して、その場でテーブルを挿入および作成できます。ただし、これを行うことには明らかなセキュリティリスクがあります...
Tigerjz32 '17

1
@nurettinストアドプロシージャが返す内容がわからない場合があります。その場合はどうなりますか?一時テーブルを作成して(ストアドプロシージャが何を返すかわからない場合)、ストアドプロシージャから挿入するにはどうすればよいでしょうか。
Tigerjz32 2017年

106

ストアドプロシージャが多くの列を返し、一時テーブルを手動で "作成"して結果を保持したくない場合は、ストアドプロシージャに移動して "into"句を最後の選択ステートメントとwhere句に1 = 0を追加します。

ストアドプロシージャを1回実行し、戻って追加したSQLコードを削除します。これで、ストアドプロシージャの結果と一致する空のテーブルが作成されます。一時テーブルの「スクリプトテーブルを作成」​​するか、そのテーブルに直接挿入することができます。


9
+1、素晴らしい提案。@TableCreateと呼ばれるsprocに簡単なオプション変数を追加することもできます。nullでない場合に上記の手順を実行するのと同じようなことを行うこともできます。一度設定すると、sprocを変更する必要はありません。
Ian Roke、

1
@dotjoe SELECT INTO一時テーブルを作成し、一時テーブルからスクリプトテーブルを作成しますか?一時テーブルが表示されtempdbますが、右クリックして作成スクリプトを実行できません。どんな助けでもありがたいです。
DotnetDude 2012

2
@DotNetDudeをselect ... into new_table使用すると、実際のテーブルを暗黙的に作成できます。
dotjoe

次に、空のテーブルスキーマから大まかな列定義を取得します。末尾の「...」を正当なTABLE_NAMEに置き換えます:declare @s varchar(max)='';select @s=@s+','+COLUMN_NAME+' '+DATA_TYPE+isnull('('+case CHARACTER_MAXIMUM_LENGTH when -1 then 'max' else cast(CHARACTER_MAXIMUM_LENGTH as varchar(10))end+')','')from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='...';select @s
user423430

これが最善の解決策です!
Lucas925

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

3
最初に一時テーブルを定義せずに挿入を行う、OPの元の質問には対応していません。
t.durden

48

ストアドプロシージャはデータを取得するだけですか、それとも変更しますか?取得のみに使用する場合は、次のように、ストアドプロシージャを関数に変換し、宣言せずに共通テーブル式(CTE)を使用できます。

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

ただし、CTEから取得する必要があるものは、1つのステートメントでのみ使用する必要があります。a 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)

1
これらは一時テーブルではなく、CTEです。 technet.microsoft.com/en-us/library/...
yucer

5
@yucerに感謝します...その当時CTEと呼ばれていたとは知らなかったと思い
ます

48

ストアドプロシージャの結果テーブルが複雑すぎて「create table」ステートメントを手動で入力できず、OPENQUERY OR OPENROWSETを使用できない場合は、sp_helpを使用して列とデータ型のリストを生成できます。列のリストを取得したら、ニーズに合わせてフォーマットするだけです。

ステップ1: "into #temp"を出力クエリに追加します(例: "select [...] into #temp from [...]")。

最も簡単な方法は、procで出力クエリを直接編集することです。ストアドプロシージャを変更できない場合は、コンテンツを新しいクエリウィンドウにコピーして、そこでクエリを変更できます。

手順2:一時テーブルでsp_helpを実行します。(例: "exec tempdb..sp_help #temp")

一時テーブルを作成した後、一時テーブルでsp_helpを実行して、varcharフィールドのサイズを含む列とデータ型のリストを取得します。

ステップ3:データの列と型をテーブル作成ステートメントにコピーする

sp_helpの出力を「create table」ステートメントにフォーマットするために使用するExcelシートがあります。特別なものは必要ありません。コピーしてSQLエディターに貼り付けてください。列名、サイズ、およびタイプを使用して、「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ステートメントを自分で書くだけの手順よりも多い場合がありますが、大規模なプロセスでのタイプミスやデータ型の不一致などの手動エラーを防ぎます。タイプミスのデバッグは、最初にクエリを書くよりも時間がかかります。


37

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を実行すると独自のセッションが作成されるため、通常の一時テーブルは後続のコードのスコープ外になるためです。グローバル一時テーブルに問題がある場合は、、通常の一時テーブルを使用ますが、後続のSQLは動的である必要があります。つまり、EXECステートメントによっても実行されます。


4
からテーブルを作成するのを忘れました@SQL
2015

32

Quassnoiはほとんどの方法で私を置きましたが、1つ欠けていました

****ストアドプロシージャでパラメーターを使用する必要がありました。****

そして、OPENQUERYはこれが起こることを許可しません:

したがって、システムを動作させる方法を見つけ、テーブル定義をそれほど厳格にする必要がなく、別のストアドプロシージャ内で再定義する必要があります(もちろん、壊れる可能性があります)。

はい、偽の変数を指定したOPENQUERYステートメントを使用して、ストアドプロシージャから返されるテーブル定義を動的に作成できます(NO RESULT SETが、適切なデータを含むデータセットと同じ数のフィールドと同じ位置にある限り)。

テーブルが作成されると、execストアドプロシージャを使用して、終日一時テーブルに格納できます。


(上記のように)データアクセスを有効にする必要があります。

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

元々提供された情報のためのおかげで... はい、最終的に私は、これらすべての偽作成する必要はありません別のストアドプロシージャまたはデータベースからのデータを使用している場合(厳密)テーブルdefintionsを、そしてはいあなたもパラメータを使用することができます。

参照タグを検索:

  • 一時テーブルへのSQL 2005ストアドプロシージャ

  • ストアドプロシージャと変数を含むopenquery 2005

  • 変数付きの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で定義、デフォルトはマスター)があるため、すべてのオブジェクト指定にはデータベース名を含める必要があります。

開いているトランザクションがあり、OPENQUERYを呼び出すときにロックを保持している場合、呼び出されたプロシージャはロックしたものにアクセスできません。つまり、注意しないと自分をブロックすることになります。

接続は無料ではないため、パフォーマンスが低下します。


1
サーバー名がわからない場合は、を使用してくださいSELECT @@SERVERNAME。次も使用できますEXEC sp_serveroption @@SERVERNAME, 'DATA ACCESS', TRUE
Contango

24

SQL 2012以降を使用できる運が良ければ、次を使用できます。 dm_exec_describe_first_result_set_for_object

gotqnが提供するsqlを編集しました。gotqnに感謝します。

これにより、プロシージャ名と同じ名前のグローバル一時テーブルが作成されます。一時テーブルは後で必要に応じて使用できます。再実行する前に削除することを忘れないでください。

    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

1
優秀な!備考:組み込みのストアドプロシージャに対してこれを実行する場合sys.all_objectssys.procedures、の代わりに使用してください。
Gert Arnold、

2
これは、SPがその中で一時テーブルを使用する場合にも失敗します。(しかし、これを武器としてprocとして持つとかなり便利です)
Trubs

23

このストアドプロシージャは次の役割を果たします。

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

これを少しやり直しました。実際に機能するように、ストアドプロシージャの結果をテーブルに挿入します

一時テーブルを使用したい場合は、##GLOBALテーブルを使用して後で削除する必要があります。


17

ストアドプロシージャの最初のレコードセットを一時テーブルに挿入するには、次のことを知っておく必要があります。

  1. ストアドプロシージャの最初の行セットのみを一時テーブルに挿入できます
  2. ストアドプロシージャは動的T-SQLステートメント(sp_executesql
  3. 最初に一時テーブルの構造を定義する必要があります

上記は制限として見えるかもしれませんが、私見はそれは完全に理にかなっています-使用しているsp_executesql場合、一度に2つの列と10を返すことができ、複数の結果セットがある場合、それらを複数のテーブルに挿入することはできません-最大を挿入できます1つのT-SQLステートメントの2つのテーブル(OUTPUT句を使用し、トリガーなし)。

したがって、問題は主に、EXEC ... INTO ...ステートメントを実行する前に一時テーブル構造を定義する方法です。

1つ目はで機能しOBJECT_ID、2つ目と3つ目はアドホッククエリでも機能します。spの代わりにDMVを使用することをお勧めしますCROSS APPLY。これは、複数のプロシージャの一時テーブル定義を同時に使用して構築できるためです。

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ステートメントが実行される場合や、一時テーブルがストアドプロシージャで使用される場合など、場合によっては最初の結果セットデータを定義できないことに注意してください。


制限に関する実用的な観察:別のspで上記のアプローチを使用して動的に作成された一時テーブルにいくつかのsp(SP_LEVEL_0と呼ぶ)の出力を挿入する必要がある場合、このSP_LEVEL_1の出力に対して同じトリックを実行することはできませんSP_LEVEL_2の別の一時テーブル
nahab

17
  1. 次のスキーマとデータでテーブルを作成しています。
  2. ストアドプロシージャを作成します。
  3. これで手順の結果がわかったので、次のクエリを実行しています。

    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;

15

クエリパラメータが含まれていない場合は、使用して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

13

コード

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

これがお役に立てば幸いです。必要に応じて修飾してください。


11

ストアドプロシージャに配列/データテーブルを渡すことがわかりましたあなたがあなたの問題を解決するに行くかもしれない方法で別のアイデアを与えるかもしれません。

リンクは画像の使用を提案していますタイプのパラメーターしてストアード・プロシージャーに渡すます。次に、ストアドプロシージャで、画像が元のデータを含むテーブル変数に変換されます。

多分これが一時テーブルで使用できる方法があるでしょう。


4
テーブル値パラメーターの導入により、Sql2008以降のバージョンではこれは不要になりました。上記のリンクで言及されているようにバイトに変換する必要があるので、.netデータセットまたはデータテーブルオブジェクトをSQLストアドプロシージャに直接渡すことができます
EndlessSpace

10

私は同じ問題に遭遇しました、そしてここに私がポールの提案からこれのためにしたことです。ここでの主な部分は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 + ']')

9

別の方法は、タイプを作成し、PIPELINEDを使用してオブジェクトを返すことです。ただし、これは列を知ることに限定されます。しかし、次のことができるという利点があります。

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

これは何ですか?この質問に関するSQL Serverとは関係がないようです
Martin Smith

8

これは単純な2ステップのプロセスです。-一時テーブルを作成します-一時テーブルに挿入します。

同じことを実行するコード:

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

反対投票; 既存の回答と非常に似ています。
iokevins

6

周りを検索した後、OPENROWSETまたはを使用せずにストアドプロシージャの一時テーブルを動的に作成する方法を見つけましたOPENQUERY特にデータベース管理者でない場合に、ストアドプロシージャの結果定義の汎用スキーマを使用、ストアドプロシージャの。

SQL Serverには、sp_describe_first_result_set任意のプロシージャの結果セットのスキーマを提供できる、組み込みのproc があります。この手順の結果からスキーマテーブルを作成し、すべてのフィールドを手動で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(ビルド17134 :)

使用しているSQLサーバーのバージョンに応じてスキーマを調整できます(必要な場合)。


4

渡されるパラメーターがわかっていて、sp_configureを実行するためのアクセス権がない場合は、これらのパラメーターを使用してストアドプロシージャを編集すると、同じものが## globalテーブルに格納されます。


3

ストアドプロシージャが1つのテーブルのみを返す場合、これはSQL Server 2014以降で実行できます。誰かが複数のテーブルに対してこれを行う方法を見つけたら、それについて知りたいです。

DECLARE @storedProcname NVARCHAR(MAX) = ''
SET @storedProcname = '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(@storedProcname),0)
FOR XML PATH('')
),1,1,'(') + ')'

EXEC (@strSQL)

INSERT INTO myTableName

EXEC ('myStoredProc @param1=1, @param2=2')

SELECT * FROM myTableName

DROP TABLE myTableName

これにより、返されたテーブルの定義がシステムテーブルからプルされ、それを使用して一時テーブルが作成されます。次に、前述のように、ストアドプロシージャからデータを入力できます。

動的SQLでも機能するこのバリアントもあります。


2

質問には数年遅れましたが、すばやく簡単にコードを生成するには、このようなものが必要でした。一時テーブルを事前に定義する方が簡単だと他の人が述べているように、この方法は単純なストアドプロシージャクエリまたはSQLステートメントで機能するはずです。

これは少し複雑になりますが、ここでの寄稿者とDBA Stack ExchangeからのPaul Whiteのソリューションを利用しています。繰り返しますが、このアプローチと例は、マルチユーザー環境でのプロセス向けに設計されたものではありません。この場合、コード生成テンプレートプロセスによる参照のために、テーブル定義がグローバル一時テーブルに短時間設定されています。

私はこれを完全にテストしていませんので、注意が必要な場合があるので、Paul Whiteの回答のMSDNリンクに移動することをお勧めします。これはSQL 2012以降に適用されます。

まず、Oracleの記述に似たストアドプロシージャsp_describe_first_result_setを使用します。

これにより、最初の結果セットの最初の行が評価されるため、ストアドプロシージャまたはステートメントが複数のクエリを返す場合、最初の結果のみが記述されます。

一時テーブル定義を作成するために選択する単一のフィールドを返すタスクを分解するストアドプロシージャを作成しました。

CREATE OR ALTER PROCEDURE [dbo].[sp_GetTableDefinitionFromSqlBatch_DescribeFirstResultSet]
(
     @sql NVARCHAR(4000)
    ,@table_name VARCHAR(100)
    ,@TableDefinition NVARCHAR(MAX) OUTPUT
)
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @TempTableDefinition NVARCHAR(MAX)
    DECLARE @NewLine NVARCHAR(4) = CHAR(13)+CHAR(10)

    DECLARE @ResultDefinition TABLE (  --The View Definition per MSDN
      is_hidden         bit NOT NULL
    , column_ordinal    int NOT NULL
    , [name]            sysname NULL
    , is_nullable       bit NOT NULL
    , system_type_id    int NOT NULL
    , system_type_name  nvarchar(256) NULL
    , max_length        smallint NOT NULL
    , [precision]       tinyint NOT NULL
    , scale             tinyint NOT 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 NOT NULL            
    , is_case_sensitive         bit NOT NULL            
    , is_fixed_length_clr_type  bit NOT 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_is_descending    smallint NULL   
    , order_by_list_length      smallint NULL
    , tds_type_id               int NOT NULL
    , tds_length                int NOT NULL
    , tds_collation_id          int NULL
    , tds_collation_sort_id     tinyint NULL
    )

    --Insert the description into table variable    
    INSERT @ResultDefinition
    EXEC sp_describe_first_result_set @sql

    --Now Build the string to create the table via union select statement
    ;WITH STMT AS (
        SELECT N'CREATE TABLE ' + @table_name + N' (' AS TextVal
        UNION ALL

        SELECT 
         CONCAT(
                CASE column_ordinal
                    WHEN 1 THEN '     ' ELSE '   , ' END  --Determines if comma should precede
                , QUOTENAME([name]) , '   ', system_type_name  -- Column Name and SQL TYPE
                ,CASE is_nullable 
                    WHEN 0 THEN '   NOT NULL' ELSE '   NULL' END --NULLABLE CONSTRAINT          
               ) AS TextVal
        FROM @ResultDefinition WHERE is_hidden = 0  -- May not be needed
        UNION ALL

        SELECT N');' + @NewLine
    ) 

    --Now Combine the rows to a single String
    SELECT @TempTableDefinition = COALESCE (@TempTableDefinition + @NewLine + TextVal, TextVal) FROM STMT

    SELECT @TableDefinition = @TempTableDefinition
END

問題は、グローバルテーブルを使用する必要があることですが、衝突を心配せずに頻繁にドロップして作成できるように、テーブルを十分に一意にする必要があります。
この例では、ハイフンをアンダースコアに置き換えるグローバル変数にGuid(FE264BF5_9C32_438F_8462_8A5DC8DEE49E)を使用しました

DECLARE @sql NVARCHAR(4000) = N'SELECT @@SERVERNAME as ServerName, GETDATE() AS Today;'
DECLARE @GlobalTempTable VARCHAR(100) = N'##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable'

--@sql can be a stored procedure name like dbo.foo without parameters

DECLARE @TableDef NVARCHAR(MAX)

DROP TABLE IF EXISTS #MyTempTable
DROP TABLE IF EXISTS ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable

EXEC [dbo].[sp_GetTableDefinitionFromSqlBatch_DescribeFirstResultSet] 
    @sql, @GlobalTempTable, @TableDef OUTPUT

--Creates the global table ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable
EXEC sp_executesql @TableDef 

--Now Call the stored procedure, SQL Statement with Params etc.
INSERT ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable
    EXEC sp_executesql @sql 

--Select the results into your undefined Temp Table from the Global Table
SELECT * 
INTO #MyTempTable
FROM ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable

SELECT * FROM #MyTempTable

DROP TABLE IF EXISTS #MyTempTable
DROP TABLE IF EXISTS ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable

繰り返しますが、私は単純なストアドプロシージャクエリと単純なクエリでのみテストしたので、実際の距離は異なる場合があります。これが誰かを助けることを願っています。


1

一時テーブルを作成する必要はありますが、適切なスキーマを持っている必要はありません...既存の一時テーブルを変更して、適切なデータを含む必要な列が含まれるようにするストアドプロシージャを作成しましたタイプと順序(すべての既存の列をドロップし、新しい列を追加):

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がストアドプロシージャの結果を判断できない場合(たとえば、一時テーブルを使用する場合)、これは機能しないことに注意してください


0

動的SQLで一時テーブルを作成すると、このテーブルは、ストアドプロシージャの呼び出し元の接続ではなく、動的SQL接続によって所有されます。

DECLARE @COMMA_SEPARATED_KEYS varchar(MAX);
DROP TABLE IF EXISTS KV;
CREATE TABLE KV (id_person int, mykey varchar(30), myvalue int);
INSERT INTO KV VALUES
(1, 'age', 16),
(1, 'weight', 63),
(1, 'height', 175),
(2, 'age', 26),
(2, 'weight', 83),
(2, 'height', 185);
WITH cte(mykey) AS (
    SELECT DISTINCT mykey FROM KV
) 
SELECT @COMMA_SEPARATED_KEYS=STRING_AGG(mykey,',') FROM cte;
SELECT @COMMA_SEPARATED_KEYS AS keys;

ここに画像の説明を入力してください

DECLARE @ExecuteExpression varchar(MAX);

DROP TABLE IF EXISTS #Pivoted;

SET @ExecuteExpression = N'
SELECT * 
INTO #Pivoted
FROM
(
    SELECT
        mykey,
        myvalue,
        id_person
    FROM KV
) AS t
PIVOT(
    MAX(t.myvalue) 
    FOR mykey IN (COMMA_SEPARATED_KEYS)
) AS pivot_table;
';

SET @ExecuteExpression = REPLACE(@ExecuteExpression, 'COMMA_SEPARATED_KEYS', @COMMA_SEPARATED_KEYS);

EXEC(@ExecuteExpression);

SELECT * FROM #Pivoted;

メッセージ208、レベル16、状態0無効なオブジェクト名 '#Pivoted'。これは、#Pivotedが動的SQL接続によって所有されているためです。だから最後の指示

SELECT * FROM #Pivoted

失敗します。

この問題に直面しない1つの方法は、#Pivotedへのすべての参照が動的クエリ自体の内部から行われるようにすることです。

DECLARE @COMMA_SEPARATED_KEYS varchar(MAX);
DROP TABLE IF EXISTS KV;
CREATE TABLE KV (id_person int, mykey varchar(30), myvalue int);
INSERT INTO KV VALUES
(1, 'age', 16),
(1, 'weight', 63),
(1, 'height', 175),
(2, 'age', 26),
(2, 'weight', 83),
(2, 'height', 185);
WITH cte(mykey) AS (
    SELECT DISTINCT mykey FROM KV
) 
SELECT @COMMA_SEPARATED_KEYS=STRING_AGG(mykey,',') FROM cte;
SELECT @COMMA_SEPARATED_KEYS AS keys;


DECLARE @ExecuteExpression varchar(MAX);

DROP TABLE IF EXISTS #Pivoted;

SET @ExecuteExpression = N'
SELECT * 
INTO #Pivoted
FROM
(
    SELECT
        mykey,
        myvalue,
        id_person
    FROM KV
) AS t
PIVOT(
    MAX(t.myvalue) 
    FOR mykey IN (COMMA_SEPARATED_KEYS)
) AS pivot_table;
SELECT * FROM #Pivoted;
';

SET @ExecuteExpression = REPLACE(@ExecuteExpression, 'COMMA_SEPARATED_KEYS', @COMMA_SEPARATED_KEYS);

EXEC(@ExecuteExpression);

ここに画像の説明を入力してください


-5

私は次のようにします

  1. UDF(テーブル値UDF)を作成(SPに変換)します。

  2. select * into #tmpBusLine from dbo.UDF_getBusinessLineHistory '16 Mar 2009'


2
最初の一歩を踏み出すにはいくつかの障害があるかもしれません。たとえば、元のSPが一時テーブルを使用する場合。UDFは一時テーブルを使用できません。
yucer 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.