RECEIVE (Transact-SQL)

適用対象: SQL Server Azure SQL Managed Instance

キューから 1 つ以上のメッセージを受信します。 キューの保有期間の設定に応じて、キューからメッセージを削除するか、キュー内のメッセージの状態を更新します。

Transact-SQL 構文表記規則

構文

[ WAITFOR ( ]  
    RECEIVE [ TOP ( n ) ]   
        <column_specifier> [ ,...n ]  
        FROM <queue>  
        [ INTO table_variable ]  
        [ WHERE {  conversation_handle = conversation_handle  
                 | conversation_group_id = conversation_group_id } ]  
[ ) ] [ , TIMEOUT timeout ]  
[ ; ]  
  
<column_specifier> ::=  
{    *   
  |  { column_name | [ ] expression } [ [ AS ] column_alias ]  
}     [ ,...n ]   
  
<queue> ::=  
{ database_name.schema_name.queue_name | schema_name.queue_name | queue_name }

引数

WAITFOR

現在メッセージが存在しない場合、RECEIVE ステートメントが、キューにメッセージが到着するのを待機するように指定します。

TOP( n )

返されるメッセージの最大数を指定します。 この句を指定しない場合、ステートメントの条件に合致したすべてのメッセージが返されます。

column_specifier

*
結果セットにキューのすべての列を含めることを指定します。

column_name
結果セットに含める列の名前です。

式 (expression)
列名、定数、関数、またはその組み合わせです。組み合わせる場合は演算子を使用します。

column_alias
結果セット内の列名を置換する別名です。

FROM

取得するメッセージが含まれているキューを指定します。

database_name
メッセージを受信するキューが含まれているデータベースの名前です。 database_name を指定しない場合、既定では現在のデータベースが使用されます。

schema_name
メッセージを受信するキューを所有するスキーマの名前です。 schema_name を指定しない場合、既定では現在のユーザーに関する既定のスキーマが使用されます。

queue_name
メッセージを受信するキューの名前です。

INTO table_variable

RECEIVE によってメッセージを格納するテーブル変数を指定します。 テーブル変数の列数は、メッセージ内の列数と同じである必要があります。 テーブル変数の各列のデータ型は、メッセージ内の対応する列のデータ型に暗黙的に変換できる必要があります。 INTO を指定しない場合、メッセージは結果セットとして返されます。

WHERE

受信するメッセージのメッセージ交換、またはメッセージ交換グループを指定します。 指定しない場合、次に使用可能なメッセージ交換グループからのメッセージが返されます。

conversation_handle = conversation_handle
受信するメッセージのメッセージ交換を指定します。 指定する conversation ハンドル は、 uniqueidentifier、または uniqueidentifierに変換できる型である必要があります。

conversation_group_id = conversation_group_id
受信するメッセージのメッセージ交換グループを指定します。 指定する conversation_group_id は、uniqueidentifer 型であるか、または uniqueidentifier に変換可能な型である必要があります。

TIMEOUT timeout

ステートメントでメッセージを待機する時間をミリ秒で指定します。 この句は WAITFOR 句と共に使用する必要があります。 この句が指定されていない場合、またはタイムアウトが -1場合、待機時間は無制限です。 タイムアウトの時間を過ぎると、RECEIVE では空の結果セットが返されます。

注釈

重要

RECEIVE ステートメントがバッチまたはストアド プロシージャで最初のステートメントではない場合は、前のステートメントの後にセミコロン (;) を指定する必要があります。

RECEIVE ステートメントでは、キューからメッセージが読み取られ、結果セットが返されます。 結果セットには 0 以上の行が含まれ、各行には 1 つのメッセージが含まれます。 INTO 句が使用されず、column_specifier でローカル変数に値が割り当てられない場合、このステートメントでは呼び出し元のプログラムに結果セットが返されます。

RECEIVE ステートメントによって返されるメッセージには、さまざまなメッセージ型があります。 アプリケーションでは、message_type_name 列を使用して、関連付けられているメッセージ型を処理するコードに各メッセージをルーティングできます。 メッセージ型には、次の 2 種類があります。

  • CREATE MESSAGE TYPE ステートメントを使用して作成されたアプリケーション定義のメッセージ型。 メッセージ交換で使用できるアプリケーション定義のメッセージ型のセットは、メッセージ交換に指定されている Service Broker コントラクトで定義されます。

  • 状態やエラー情報を返す Service Broker システム メッセージ。

キューにメッセージ保有期間が指定されていない場合、RECEIVE ステートメントでは受信したメッセージがキューから削除されます。 キューの RETENTION 設定が ON になっている場合、RECEIVE ステートメントでは status 列が 0 に更新され、メッセージはキューに残ります。 RECEIVE ステートメントを含むトランザクションがロールバックされる場合は、そのトランザクションでキューに行われたすべての変更もロールバックされ、キューにメッセージが戻されます。

RECEIVE ステートメントで返されるメッセージは、すべて同じメッセージ交換グループに属しています。 RECEIVE ステートメントでは、ステートメントを含むトランザクションが完了するまで、返されるメッセージのメッセージ交換グループがロックされます。 RECEIVE ステートメントでは、status1 のメッセージが返されます。 RECEIVE ステートメントで返された結果セットは暗黙的に並べ替えられます。

  • 複数のメッセージ交換のメッセージが WHERE 句の条件を満たす場合、RECEIVE ステートメントでは、1 つのメッセージ交換のメッセージがすべて返されてから、他のメッセージ交換のメッセージが返されます。 メッセージ交換は、優先度レベルの降順に処理されます。

  • 指定されたメッセージ交換に対して、RECEIVE ステートメントでは、メッセージが message_sequence_number の値で昇順に並べ替えられて返されます。

RECEIVE ステートメントの WHERE 句には、conversation_handle または conversation_group_id のいずれかを使用した検索条件を 1 つだけ含めることができます。 検索条件にキューの他の列を 1 つ以上含めることはできません。 conversation_handle または conversation_group_id には、式を指定することはできません。 返されるメッセージのセットは、WHERE 句で指定した条件によって決まります。

  • conversation_handle を指定した場合、RECEIVE では、指定したメッセージ交換から、キュー内の使用できるメッセージがすべて返されます。

  • conversation_group_id を指定した場合、RECEIVE では、指定したメッセージ交換グループのメンバーである任意のメッセージ交換から、キュー内の使用できるメッセージがすべて返されます。

  • WHERE 句がない場合は、RECEIVE によって、次の条件を満たすメッセージ交換グループに決定されます。

    • 1 つ以上のメッセージがキュー内にある。

    • 別の RECEIVE ステートメントによってロックされていない。

    • 上記の条件を満たすすべてのメッセージ交換グループのうち、最も高い優先度レベルを持つ。

    決定後、RECEIVE によって、選択されたメッセージ交換グループのメンバーである任意のメッセージ交換から、キュー内の使用できるメッセージがすべて返されます。

WHERE 句で指定したメッセージ交換ハンドルまたはメッセージ交換グループの識別子が存在しないか、指定したキューに関連付けられていない場合、RECEIVE ステートメントではエラーが返されます。

RECEIVE ステートメントで指定したキューの状態が OFF に設定されている場合、ステートメントは失敗し、Transact-SQL エラーが返されます。

WAITFOR 句を指定した場合、ステートメントは指定のタイムアウト時間が経過するか結果セットが使用可能になるまで待機します。 ステートメントが待機しているときに、キューが削除されたり、キューの状態が OFF に設定されると、ステートメントでは直ちにエラーが返されます。 RECEIVE ステートメントでメッセージ交換グループまたはメッセージ交換ハンドルを指定したが、メッセージ交換で使用するサービスが削除されたり、他のキューに移動された場合、RECEIVE ステートメントでは Transact-SQL エラーがレポートされます。

RECEIVE は、ユーザー定義の関数では無効です。

RECEIVE ステートメントには、優先度のスタベーション防止はありません。 1 つの RECEIVE ステートメントによってメッセージ交換グループがロックされ、優先度の低いメッセージ交換から大量のメッセージが取得されると、そのグループ内の優先度の高いメッセージ交換からメッセージを受信できなくなります。 このような状態を回避するには、優先度の低いメッセージ交換からメッセージを取得する場合に、TOP 句を使用して、各 RECEIVE ステートメントによって取得されるメッセージ数を制限します。

キューの列

次の表は、キューの列の一覧です。

列名 データ型 説明
status tinyint メッセージの状態。 RECEIVE コマンドによって返されるメッセージの場合、状態は常に 0。 キューのメッセージには、次のいずれかの値を含めることができます。

0=Ready
1=受信したメッセージ
2=まだ完了していない
3=送信済みメッセージを保持
priority tinyint メッセージに適用されているメッセージ交換の優先度レベル。
queuing_order bigint キュー内のメッセージの順序番号。
conversation_group_id uniqueidentifier メッセージが属するメッセージ交換グループの識別子。
conversation_handle uniqueidentifier メッセージが属するメッセージ交換のハンドル。
message_sequence_number bigint メッセージ交換内でのメッセージのシーケンス番号。
service_name nvarchar(128) メッセージ交換の対象サービスの名前。
service_id int メッセージ交換の対象サービスに関する SQL Server オブジェクト識別子。
service_contract_name nvarchar(128) メッセージ交換が従うコントラクトの名前。
service_contract_id int メッセージ交換が従うコントラクトに関する SQL Server オブジェクト識別子。
message_type_name nvarchar(128) メッセージの形式を示すメッセージ型の名前。 メッセージは、アプリケーション メッセージ型か Broker システム メッセージのいずれかになります。
message_type_id int メッセージの種類を示すメッセージ型に関する SQL Server オブジェクト識別子。
validation nchar(2) メッセージに使用される検証。

E=Empty
N=None
X=XML
message_body varbinary(MAX) メッセージの内容。

アクセス許可

メッセージを受信するには、キューに対する RECEIVE 権限が必要です。

A. 会話グループ内のすべてのメッセージのすべての列を受信する

次の例では、ExpenseQueue キューから、次に使用できるメッセージ交換グループに属している使用可能なすべてのメッセージを受信します。 このステートメントでは、メッセージが結果セットとして返されます。

RECEIVE * FROM ExpenseQueue ;  

B. 会話グループ内のすべてのメッセージに対して指定された列を受信する

次の例では、ExpenseQueue キューから、次に使用できるメッセージ交換グループに属している使用可能なすべてのメッセージを受信します。 このステートメントでは、列 conversation_handlemessage_type_namemessage_body を含むメッセージが結果セットとして返されます。

RECEIVE conversation_handle, message_type_name, message_body  
FROM ExpenseQueue ;  

C: キューで最初に使用可能なメッセージを受信する

次の例では、ExpenseQueue キューから、最初に使用可能なメッセージを結果セットとして受信します。

RECEIVE TOP (1) * FROM ExpenseQueue ;  

D. 指定した会話のすべてのメッセージを受信する

次の例では、ExpenseQueue キューから、指定したメッセージ交換に属している使用可能なすべてのメッセージを結果セットとして受信します。

DECLARE @conversation_handle UNIQUEIDENTIFIER ;  
  
SET @conversation_handle = <retrieve conversation from database> ;  
  
RECEIVE *  
FROM ExpenseQueue  
WHERE conversation_handle = @conversation_handle ;  

E. 指定した会話グループのメッセージを受信する

次の例では、ExpenseQueue キューから、指定したメッセージ交換グループに属している使用可能なすべてのメッセージを結果セットとして受信します。

DECLARE @conversation_group_id UNIQUEIDENTIFIER ;  
  
SET @conversation_group_id =   
    <retrieve conversation group ID from database> ;  
  
RECEIVE *  
FROM ExpenseQueue  
WHERE conversation_group_id = @conversation_group_id ;  

F. テーブル変数への受信

次の例では、ExpenseQueue キューから、指定したメッセージ交換グループに属している使用可能なすべてのメッセージを受信して、テーブル変数に挿入します。

DECLARE @conversation_group_id UNIQUEIDENTIFIER ;  
  
DECLARE @procTable TABLE(  
     service_instance_id UNIQUEIDENTIFIER,  
     handle UNIQUEIDENTIFIER,  
     message_sequence_number BIGINT,  
     service_name NVARCHAR(512),  
     service_contract_name NVARCHAR(256),  
     message_type_name NVARCHAR(256),  
     validation NCHAR,  
     message_body VARBINARY(MAX)) ;  
  
SET @conversation_group_id = <retrieve conversation group ID from database> ;  
  
RECEIVE TOP (1)  
    conversation_group_id,  
    conversation_handle,  
    message_sequence_number,  
    service_name,  
    service_contract_name,  
    message_type_name,  
    validation,  
    message_body  
FROM ExpenseQueue  
INTO @procTable  
WHERE conversation_group_id = @conversation_group_id ;  

G. メッセージを受信し、無期限に待機する

次の例では、ExpenseQueue キューから、次に使用できるメッセージ交換グループに属している使用可能なすべてのメッセージを受信します。 このステートメントは、少なくとも 1 つのメッセージが使用可能になるまで待機し、その後すべてのメッセージ列を含む結果セットを返します。

WAITFOR (  
    RECEIVE *  
    FROM ExpenseQueue) ;  

H. メッセージの受信と指定した間隔の待機

次の例では、ExpenseQueue キューから、次に使用できるメッセージ交換グループに属している使用可能なすべてのメッセージを受信します。 このステートメントは、60 秒が経過するか、少なくとも 1 つのメッセージが使用可能になるまで待機します。 少なくとも 1 つのメッセージが使用可能である場合、このステートメントはすべてのメッセージ列を含む結果セットを返します。 それ以外の場合は、空の結果セットを返します。

WAITFOR (  
    RECEIVE *  
    FROM ExpenseQueue ),  
TIMEOUT 60000 ;  

I. メッセージを受信し、列の型を変更する

次の例では、ExpenseQueue キューから、次に使用できるメッセージ交換グループに属している使用可能なすべてのメッセージを受信します。 メッセージ型でメッセージに XML ドキュメントが含まれることが指定されている場合、このステートメントでは、メッセージ本文が XML に変換されます。

WAITFOR (  
    RECEIVE message_type_name,  
        CASE  
            WHEN validation = 'X' THEN CAST(message_body as XML)  
            ELSE NULL  
         END AS message_body   
         FROM ExpenseQueue ),  
TIMEOUT 60000 ;  

J. メッセージの受信、メッセージ本文からのデータの抽出、会話状態の取得

次の例では、ExpenseQueue キューから、次に使用できるメッセージ交換グループに属している、次に使用可能なメッセージを取得します。 メッセージの型が //Adventure-Works.com/Expenses/SubmitExpense の場合、このステートメントでは、メッセージ本文から従業員 ID とアイテム一覧が抽出されます。 また、このステートメントでは ConversationState テーブルからメッセージ交換の状態も取得されます。

WAITFOR(  
    RECEIVE   
    TOP(1)  
      message_type_name,  
      COALESCE(  
           (SELECT TOP(1) ConversationState  
            FROM CurrentConversations AS cc  
            WHERE cc.ConversationHandle = conversation_handle),  
           'NEW')  
      AS ConversationState,  
      COALESCE(  
          (SELECT TOP(1) ErrorCount  
           FROM CurrentConversations AS cc  
           WHERE cc.ConversationHandle = conversation_handle),   
           0)  
      AS ConversationErrors,  
      CASE WHEN message_type_name = N'//Adventure-Works.com/Expenses/SubmitExpense'  
          THEN CAST(message_body AS XML).value(  
                'declare namespace rpt = "https://Adventure-Works.com/schemas/expenseReport"  
                   (/rpt:ExpenseReport/rpt:EmployeeID)[1]', 'nvarchar(20)')  
         ELSE NULL  
      END AS EmployeeID,  
      CASE WHEN message_type_name = N'//Adventure-Works.com/Expenses/SubmitExpense'  
          THEN CAST(message_body AS XML).query(  
                'declare namespace rpt = "https://Adventure-Works.com/schemas/expenseReport"   
                     /rpt:ExpenseReport/rpt:ItemDetail')  
          ELSE NULL  
      END AS ItemList  
    FROM ExpenseQueue   
), TIMEOUT 60000 ;