ストアドプロシージャから表形式のデータを渡す

プロシージャの結果をテーブル形式で取得して、SQLで処理する方法について説明します。 上記のほとんどは、複雑なSQLロジックと膨大な手順を備えたアプリケーションでのみ役立つと思います。 これらの方法が最も効果的だとは言えません。 これは私が仕事で使うものです。 これはすべてMicrosoft SQL Server 2008で機能します。

トピックに精通している人のために、5番目の方法まで投稿をスクロールすることをお勧めします。



データを取得する必要がある手順を次のようにします。

create procedure Proc1 as begin select 1 p1, 'b' p2 end
      
      





1方法



最も簡単な方法の1つ。 insert ... exec ...



コンストラクトの使用

 if object_id(N'tempdb..#t1',N'U') is not null drop table #t1 create table #t1(p1 int, p2 varchar(max)) insert #t1 exec Proc1 select * from #t1
      
      





長所と短所:






2方法



以前に作成したテーブルに書き込む。 ここで、プロシージャに挿入を追加する必要があります。

 create procedure Proc1 as begin insert #t1(p1, p2) select 1 p1, 'b' p2 end
      
      





基本的に、プロシージャ内に挿入行をラップします。

 if object_id(N'tempdb..#t1',N'U') is not null drop table #t1 create table #t1(p1 int, p2 varchar(max)) exec Proc1 select * from #t1
      
      





長所と短所:




 alter procedure Proc1 as begin declare @show bit if object_id(N'tempdb..#t1',N'U') is null begin set @show = 1 create table #t1(p1 int, p2 varchar(max)) end insert #t1(p1, p2) select 1 p1, 'b' p2 if (@show = 1) begin select * from #t1 end end
      
      





私は、永続的なテーブルを介して転送する可能性を考慮していません。 必要に応じて、タスクはこのトピックに関係しません。 そうでない場合は、セッション間のロックと認証に関する不要な問題が発生します。



3方法



実際、これは2番目の方法の改良版です。 サポートを簡素化するには、カスタムテーブルタイプを作成します。 次のようになります。

 create type tt1 as table(p1 int, p2 varchar(max)) go create procedure Proc1 as begin insert #t1(p1, p2) select 1 p1, 'b' p2 end go -- : declare @t1 tt1 if object_id(N'tempdb..#t1',N'U') is not null drop table #t1 select * into #t1 from @t1 exec Proc1 select * from #t1
      
      





長所と短所:






4方法



3番目の方法の複雑さ。制限とインデックスを持つテーブルを作成できます。 前のものとは異なり、Microsoft SQL Server 2005で動作します。

 create procedure Proc1 as begin insert #t1(p1, p2) select 1 p1, 'b' p2 end go create procedure Proc1_AlterTable as begin alter table #t1 add p1 int, p2 varchar(max) alter table #t1 drop column delmy end go -- : if object_id(N'tempdb..#t1',N'U') is not null drop table #t1 create table #t1(delmy int) exec Proc1_AlterTable exec Proc1 select * from #t1
      
      





ただし、通常、delmy一時列は使用されず、代わりに1つの最初の列(ここではp1)でテーブルが作成されます。



長所と短所:






5方法



このメソッドは、事前に作成されたプロシージャを使用します。 これは、実行中のプロシージャに動的SQLクエリを含めることに基づいています。 ただし、非常に使いやすいです。



それを使用するには、手順を次のように処理する必要があります。



1.手順の最初に、次の行を含めます。

 if object_id('tempdb..#ttInclusion', 'U') is null create table #ttInclusion(lvl int, i int) exec util.InclusionBegin
      
      





2.出力を選択するすべてのプロシージャを再実行して、 into #Output5



で始まる一時テーブルを作成します(たとえば、 into #Output5



into #Output5



into #Output5



に)。 プロシージャが結果セットを作成しない場合、アクションは不要です。

3.手順の最後に、次の行を含めます。

 exec util.InclusionEnd --  ,   #Output,       util.InclusionBegin
      
      





この例では、次を取得します。

 create procedure Proc1 as begin if object_id('tempdb..#ttInclusion', 'U') is null create table #ttInclusion(lvl int, i int) exec util.InclusionBegin select 1 p1, 'b' p2 into #Output1 exec util.InclusionEnd --  ,   #Output,       util.InclusionBegin end
      
      





起動は次のとおりです。

 if object_id('tempdb..#ttInclusionParameters', 'U') is null create table #ttInclusionParameters(lvl int, pr int, val varchar(max)) exec util.InclusionRun' select * from #InclusionOutput1 ', 1, '#InclusionOutput' exec Proc1
      
      





生成されたSQLは常に良いとは限らないため、上記の例は小さな命令に適しています。 大量のコードがある場合は、それを別のプロシージャに削除して動的部分からのみexec呼び出しを実行するか、データを新しい一時テーブルにリロードできます。 後者の場合、当然、別の「余分な」コピーが発生しますが、この段階で結果を事前にグループ化し、さらに処理するために必要なフィールドのみを選択できることがよくあります(たとえば、返されるデータがすべて不要な場合など) )



util.InclusionRun



関数には3つのパラメーターが渡されます。





作業は、最初にProc1



を実行せずにProc1



を実行すると、処理前に出力されるすべてのデータを出力するプロシージャの自然な操作につながるように構成されています。



使用のニュアンス:






長所と短所:






使用のデモンストレーション:


非表示のテキスト
コード:

 if object_id('dbo.TestInclusion') is not null drop procedure dbo.TestInclusion go create procedure dbo.TestInclusion @i int as begin if object_id('tempdb..#ttInclusion', 'U') is null create table #ttInclusion(lvl int, i int) exec util.InclusionBegin if object_id('tempdb..#tmp2', 'U') is not null drop table #tmp2 select @i myI into #tmp2 if object_id('tempdb..#tmp3', 'U') is not null drop table #tmp3 select @i + 1 myI into #tmp3 select * into #Output0 --  (  util.InclusionEnd) from #tmp2 union all select * from #tmp3 select ' TestInclusion' alt into #OutputQwerty --  (  util.InclusionEnd) exec util.InclusionEnd --     #Output       util.InclusionBegin end go set nocount on set ansi_warnings off if object_id('tempdb..#ttInclusionParameters', 'U') is not null drop table #ttInclusionParameters go select ' 1:  TestInclusion.         myI   : 2  3.    1 : " TestInclusion"' exec dbo.TestInclusion 2 go select ' 2:  TestInclusion.         testSum   : 5' if object_id('tempdb..#ttInclusionParameters', 'U') is null create table #ttInclusionParameters(lvl int, pr int, val varchar(max)) exec util.InclusionRun ' select sum(myI) testSum from #InclusionOutput1 ', 1, '#InclusionOutput' exec dbo.TestInclusion 2
      
      







結果:

 -----------------------------------------------------------------------------------------------------------------------------------------------------------  1:  TestInclusion.         myI   : 2  3.    1 : " TestInclusion" myI ----------- 2 3 alt -----------------------  TestInclusion ------------------------------------------------------------------------------------------------------  2:  TestInclusion.         testSum   : 5 testSum ----------- 5
      
      









機能自体:


非表示のテキスト
 if not exists(select top 1 null from sys.schemas where name = 'util') begin exec ('create schema util') end go alter procedure util.InclusionBegin as begin /*   : 1.       1.1.     : if object_id('tempdb..#ttInclusion', 'U') is null create table #ttInclusion(lvl int, i int) exec util.InclusionBegin 1.1.   select'         #Output ( into #Output, into #Output5, into #OutputMySelect) 1.2.     : exec util.InclusionEnd --  ,   #Output,       util.InclusionBegin 2.  ,    ,       (      #Output* ): if object_id('tempdb..#ttInclusionParameters', 'U') is null create table #ttInclusionParameters(lvl int, pr int) exec util.InclusionRun('<sql         >')  .   util.InclusionRun */ set nocount on set ansi_warnings off declare @lvl int if object_id('tempdb..#ttInclusionParameters', 'U') is not null begin select @lvl = max(lvl) from #ttInclusionParameters -- null ,           if (@lvl is not null) begin insert #ttInclusionParameters(lvl, pr) select @lvl+1 lvl, null pr end end if object_id('tempdb..#ttInclusion', 'U') is not null begin --     #Output,   util.InclusionEnd    insert #ttInclusion(lvl, i) select isnull(@lvl, 0), so.object_id i from tempdb.sys.objects so where so.type = 'U' and so.name like '#[^#]%' and object_id('tempdb..' + so.name, 'U') is not null and not exists (select top 1 null from #ttInclusion where i = so.object_id) end end GO go alter procedure util.InclusionEnd as begin /*   : 1.       1.1.     : if object_id('tempdb..#ttInclusion', 'U') is null create table #ttInclusion(lvl int, i int) exec util.InclusionBegin 1.1.   select'         #Output ( into #Output, into #Output5, into #OutputMySelect) 1.2.     : exec util.InclusionEnd --  ,   #Output,       util.InclusionBegin 2.  ,    ,       (      #Output* ): if object_id('tempdb..#ttInclusionParameters', 'U') is null create table #ttInclusionParameters(lvl int, pr int) exec util.InclusionRun('<sql         >')  .   util.InclusionRun */ set nocount on set ansi_warnings off ---------------------------------------------------------------------------------------------------- --  declare @lvl int , @p0 varchar(max) --(@sql) sql     , @p1 varchar(max) --(@notShowOutput)   '1'        ,    #Output,    , @p2 varchar(max) --(@replaceableTableName)    if object_id('tempdb..#ttInclusionParameters', 'U') is not null begin --   select @p1 = max(val) from #ttInclusionParameters where pr = 1 --      (max(lvl) -    null     util.InclusionBegin) select @lvl = max(lvl) - 1 from #ttInclusionParameters if @lvl is not null begin -- select @p0 = max(case when pr = 0 then val end) , @p2 = max(case when pr = 2 then val end) from #ttInclusionParameters where lvl = @lvl having max(pr) is not null --   ,    ,   null- delete #ttInclusionParameters where lvl >= @lvl and (lvl > @lvl or @p0 is not null) end end ---------------------------------------------------------------------------------------------------- --    #Output if object_id('tempdb..#InclusionOutputs', 'U') is not null drop table #InclusionOutputs create table #InclusionOutputs(i int, tableName varchar(max), num int) if object_id('tempdb..#ttInclusion', 'U') is not null begin insert #InclusionOutputs(i, tableName, num) select so.object_id i, left(so.name, charindex('_', so.name)-1) tableName, row_number() over (order by so.create_date) num from tempdb.sys.objects so where so.type = 'U' and so.name like '#[^#]%' and object_id('tempdb..' + so.name, 'U') is not null and so.name like '#Output%' and not exists (select top 1 null from #ttInclusion where i = so.object_id and lvl <= isnull(@lvl, lvl)) --   ,     delete #ttInclusion where lvl <= @lvl end else begin insert #InclusionOutputs(i, tableName, num) select so.object_id i, left(so.name, charindex('_', so.name)-1) tableName, row_number() over (order by so.create_date) num from tempdb.sys.objects so where so.type = 'U' and so.name like '#[^#]%' and object_id('tempdb..' + so.name, 'U') is not null and so.name like '#Output%' end ---------------------------------------------------------------------------------------------------- --  (    -   #Output) declare @srcsql varchar(max) --    util.InclusionRun if (@p0 is not null and @p0 <> '') begin --  @replaceableTableName if (@p2 is not null and @p2 <> '') begin select @p0 = replace(@p0, @p2 + cast(num as varchar(10)), replace(tableName, '#', '#<tokenAfterReplace>')) from #InclusionOutputs order by num desc select @p0 = replace(@p0, '<tokenAfterReplace>', '') end --   select @srcsql = isnull(@srcsql + ' ' + char(13), '') + @p0 + ' ' + char(13) end --  #Output  if (@p1 is null or @p1 <> '1') --  1,   ! begin --    select @srcsql = isnull(@srcsql + ' ' + char(13), '') --   select @srcsql = isnull(@srcsql + ' ', '') + 'select * from ' + tableName from #InclusionOutputs order by num asc end if (@srcsql is not null) begin exec (@srcsql) end end go alter procedure util.InclusionRun @sql varchar(max), --sql       ( util.InclusionEnd) @notShowOutput bit, -- = 1,       #Output @replaceableTableName varchar(100) = '#Output' --        @sql,      #Output*   . -- ,   #InclusionOutput,       #Output55  #Output0A, --   @sql    #Output55   #InclusionOutput1,   #Output0A   #InclusionOutput2 as begin set nocount on set ansi_warnings off if object_id('tempdb..#ttInclusionParameters', 'U') is null begin print ' util.InclusionRun  , ..      #ttInclusionParameters! ' return end declare @lvl int select @lvl = isnull(max(lvl), 0) + 1 from #ttInclusionParameters insert #ttInclusionParameters(lvl, pr, val) select @lvl, 0, @sql union all select @lvl, 1, '1' where @notShowOutput = 1 union all select @lvl, 2, @replaceableTableName end
      
      









その他の方法



OUTPUT



)関数からのパラメーター転送を使用して、その値に基づいてテーブルを復元できます。 たとえば、カーソルまたはXMLを渡すことができます。

このテーマに関する記事があります。

このタスクにカーソルを使用するには、最初にカーソルが必要な場合にのみ理由がわかります。 しかし、XMLは有望に見えます。 以下は、非常に興味深いパフォーマンステストの結果です。

このタスクを簡素化するために使用する方法を聞くのは興味深いです:)



UPD 03/31/2014:コメントからのアイデアに関する投稿を修正



All Articles