web-dev-qa-db-ja.com

ストアドプロシージャから一時テーブルを返す方法

CREATE PROCEDURE [test].[proc]
@ConfiguredContentId int,
@NumberOfGames int
AS
BEGIN
 SET NOCOUNT ON
 RETURN 
 @WunNumbers TABLE (WinNumb int)

    INSERT INTO @WunNumbers (WinNumb)
 SELECT TOP (@NumberOfGames) WinningNumber
 FROM [Game].[Game] g
 JOIN [Game].[RouletteResult] AS rr ON g.[Id] = rr.[gameId]
 WHERE g.[ConfiguredContentId] = @ConfiguredContentId
 ORDER BY g.[Stoptime] DESC

 SELECT WinNumb, COUNT (WinNumb) AS "Count"
 FROM @WunNumbers wn
 GROUP BY wn.[WinNumb]
END
GO

このストアドプロシージャは、最初のselectステートメントから値を返しますが、2番目のselectステートメントから値を返したいです。テーブル@WunNumbersは一時テーブルです。

何か案は???

15
dani

使用しているSQL Serverのバージョンは何ですか? SQL Server 2008では、 テーブルパラメーターとテーブルタイプ を使用できます。

別のアプローチは、ユーザー定義関数からテーブル変数を返すことですが、私はこのメソッドの大ファンではありません。

例を見つけることができます here

6
John Sansom

このコードを見てください、

CREATE PROCEDURE Test

AS
    DECLARE @tab table (no int, name varchar(30))

    insert @tab  select eno,ename from emp  

    select * from @tab
RETURN
27
adatapost

一時テーブルは、呼び出し元で作成し、呼び出されたSPから作成できます。

  create table #GetValuesOutputTable(
     ...   
  );

  exec GetValues; -- populates #GetValuesOutputTable

  select * from #GetValuesOutputTable;

「execの挿入」に対するこのアプローチのいくつかの利点は、ネストできること、および入力または出力として使用できることです。

いくつかの欠点は、「引数」がパブリックではないこと、テーブルの作成が各呼び出し元内に存在すること、およびテーブルの名前が他の一時オブジェクトと衝突する可能性があることです。これは、一時テーブル名がSP名前と厳密に一致し、いくつかの規則に従う場合に役立ちます。

少し詳しく説明すると、一時テーブルのみを出力する場合は、呼び出されたSPがinsert-execアプローチとtempテーブルアプローチを同時にサポートできます。これは、呼び出し元でテーブルを定義する必要があるため、SPのチェーンにはあまり役立ちませんが、cmd行からのテストや外部からの呼び出しを簡単にするのに役立ちます。

  -- The "called" SP
  declare
      @returnAsSelect bit = 0;

  if object_id('tempdb..#GetValuesOutputTable') is null
  begin
      set @returnAsSelect = 1;
      create table #GetValuesOutputTable(
         ...   
      );
  end

  -- populate the table

  if @returnAsSelect = 1
      select * from #GetValuesOutputTable;
3
crokusek

まず、返される一時テーブルに必要なレイアウトを持つテンプレートとして実際の永続テーブルを作成します。テンプレートとして識別し、SPにシンボリックにリンクする命名規則を使用します(例:tmp_SPName_Output)。このテーブルにはデータが含まれません。

SPでは、INSERTを使用して、同じ命名規則に従ってデータを一時テーブルにロードします。 #SPName_Outputこれは存在すると想定されています。その存在をテストし、存在しない場合はエラーを返すことができます。

Spを呼び出す前に、この単純な選択を使用して一時テーブルを作成します。

SELECT TOP(0) * INTO #SPName_Output FROM tmp_SPName_Output;
EXEC SPName;
-- Now process records in #SPName_Output;

これには、次の明確な利点があります。

  • 一時テーブルは##とは異なり、現在のセッションに対してローカルであるため、異なるセッションからのSPへの同時呼び出しと衝突しません。また、スコープ外の場合は自動的に削除されます。
  • テンプレートテーブルはSPと一緒に保持されるため、出力に変更が加えられた場合(たとえば、新しい列が追加された場合)、SPの既存の呼び出し元は壊れません。呼び出し元は変更する必要があります。
  • 1つのSPに異なる名前を付けて任意の数の出力テーブルを定義し、それらすべてを埋めることができます。また、異なる名前を付けてSP一時テーブルの存在を確認して、どのテーブルに入力する必要があるかを確認してください。
  • 同様に、大きな変更が行われたが後方互換性を維持したい場合は、新しいテンプレートテーブルと新しいバージョンの名前を付けることができますが、呼び出し元が作成した一時テーブルをチェックすることで以前のバージョンをサポートできます。
1
JohnRC

プロシージャの戻り値の型はintです。

また、結果セットを返すことができます(現在のコードのように)(大丈夫、文字列であるメッセージを送信することもできます)

それらはあなたが作ることができる唯一の「リターン」です。テーブル値のパラメーターをプロシージャに追加できますが(BOLを参照)、それらは入力専用です。

編集:

(または別のポスターで述べたように、プロシージャではなくテーブル値関数を使用することもできます)

はい、できます

ストアドプロシージャで、テーブル@tbRetour

ストアドプロシージャの最後に、次のように記述します。

SELECT * FROM @tbRetour 

ストアドプロシージャを実行するには、次のように記述します。

USE [...]
GO

DECLARE @return_value int

EXEC @return_value = [dbo].[getEnregistrementWithDetails]
@id_enregistrement_entete = '(guid)'

GO
0
André Millaire