Skip to main content

This documentation is for an older version of this product. See the latest version of this content.Opens in a new tab

クラス・クエリの定義と使用

この章では、クラス・クエリについて説明します。クラス・クエリは、クラス構造の一部である名前付きクエリとして機能し、ダイナミック SQL を通じてアクセスできます。

クラス・クエリの概要

クラス・クエリとは、ダイナミック SQL と共に使用することを目的として、クラスに含まれているツールです。これにより、指定した条件を満たすレコードを検索します。クラス・クエリを使用すると、アプリケーションに応じて事前に定義した検索を作成できます。例えば、名前でレコードを検索したり、特定の条件のセット (パリからマドリッドまでのすべての航空便など) を満たすレコードのリストを提供したりできます。

クラス・クエリを作成することで、特定のオブジェクトの内部 ID を使用してそのオブジェクトの検索を避けることができます。その代わり、必要とする任意のクラス・プロパティに基づいて検索するクエリを作成できます。これは、実行時にユーザによって指定することも可能です。

カスタム・クラス・クエリを定義すると、検索ロジックに ObjectScript を使用することも、検索ロジックを任意の複合式にすることもできます。

クラス・クエリには、以下の 2 種類があります。

クラス・クエリはどのクラス内でも定義できます。クラス・クエリは永続クラス内に含める必要はありません。

Important:

別のクラス・クエリの結果に依存するクラス・クエリを定義しないでください。このような依存関係はサポートされません。

クラス・クエリの使用法

クラス・クエリを定義する方法について説明する前に、その使用方法を知っておくと便利です。サーバ側のコードでは、以下のようにクラス・クエリを使用できます。

  1. %New() を使用して、%SQL.StatementOpens in a new tab のインスタンスを作成します。

  2. そのインスタンスの %PrepareClassQuery() メソッドを呼び出します。引数として、以下をこの順番で使用します。

    1. 使用するクエリを定義しているクラスの完全修飾名。

    2. そのクラスに含まれるクエリの名前。

    このメソッドは %StatusOpens in a new tab 値を返すので、その値を確認する必要があります。

  3. %SQL.StatementOpens in a new tab インスタンスの %Execute() メソッドを呼び出します。これにより %SQL.StatementResultOpens in a new tab のインスタンスが返されます。

  4. %SQL.StatementResultOpens in a new tab のメソッドを使用して、結果セットからデータを取得します。詳細は、"InterSystems SQL の使用法" の “ダイナミック SQL” を参照してください。

以下に、使用できる簡単な例を示します。この例では、Sample.PersonByName クエリを使用します。

  // classquerydemo
  set statement = ##class(%SQL.Statement).%New()
  set status = statement.%PrepareClassQuery("Sample.Person","ByName")
  if $$$ISERR(status) {write "%Prepare failed:" do $SYSTEM.Status.DisplayError(status) quit}

  set rset = statement.%Execute()
  if (rset.%SQLCODE '= 0) {write "%Execute failed:", !, "SQLCODE ", rset.%SQLCODE, ": ", rset.%Message quit}

  while rset.%Next()
  {
    write !, rset.%Get("Name")
  }
  if (rset.%SQLCODE < 0) {write "%Next failed:", !, "SQLCODE ", rset.%SQLCODE, ": ", rset.%Message quit}

クエリに SqlProc のマークが付けられている (クエリが ODBC または JDBC ストアド・プロシージャとして定義されている) 場合、そのクエリは SQL コンテキストからストアド・プロシージャとして呼び出すことができます。"InterSystems SQL の使用法" の "ストアド・プロシージャの定義と使用" を参照してください。

基本クラス・クエリの定義

基本クラス・クエリを定義するには、以下のようにクエリを定義します。

  • (単純なクラス・クエリの場合) タイプは %SQLQueryOpens in a new tab にする必要があります。

  • 引数リストに、クエリが受け入れる引数を指定します。

  • 定義の本文に、SQL SELECT 文を記述します。

    この文では、引数名の先頭にコロン (:) を付けて、引数を参照します。

    この SELECT 文には、INTO 節を含めないでください。

  • クエリの ROWSPEC パラメータを指定します (クエリ・タイプの後の括弧内で指定します)。このパラメータは、クエリの結果セットの各行に含まれるフィールドの名前、データ型、ヘッダ、および順序に関する情報を提供します。詳細は、2 番目のサブセクションで説明します。

  • 必要に応じて、クエリの CONTAINID パラメータを指定します (クエリ・タイプの後の括弧内で指定します)。このパラメータでは、特定の行の ID を格納するフィールドの列番号を指定します (フィールドが存在する場合)。既定値は 1 です。詳細は、3 番目のサブセクションで説明します。

    ROWSPEC パラメータと CONTAINID パラメータをまとめて、クエリ仕様と呼びます。

  • クエリ定義に SqlProc キーワードを含めます。

    %SQL.StatementOpens in a new tab を使用するクエリの呼び出しを計画している場合は、SqlProc キーワードを指定する必要があります

  • オプションとして、ストアド・プロシージャに既定の名前とは別の名前を付ける場合は、クエリ定義内で SqlName キーワードを指定します。

    これらは、コンパイラ・キーワードであるため、クエリ・タイプ (%SQLQueryOpens in a new tab) の後のパラメータに続く角括弧の内側に含めます。

以下のサブセクションに例を示します。

以下に簡単な例を示します。

Query ListEmployees(City As %String = "") 
   As %SQLQuery (ROWSPEC="ID:%Integer,Name:%String,Title:%String", CONTAINID = 1) [SqlProc, SqlName=MyProcedureName]
{
SELECT ID,Name,Title FROM Employee
 WHERE (Home_City %STARTSWITH :City)
 ORDER BY Name
}
Note:

ADO.NET、ODBC、または JDBC を使用してクラス・クエリを呼び出す場合、既定では、文字列パラメータが 50 文字に切り捨てられます。パラメータの最大文字列長を長くするには、以下の例のようにシグニチャで MAXLEN を指定します。

Query MyQuery(MyParm As %String(MAXLEN = 200)) As %SQLQuery [SqlProc]

管理ポータルまたは ObjectScript からクエリを呼び出す場合、この切り捨ては行われません。

ROWSPEC パラメータ

クエリの ROWSPEC パラメータでは、各行に含まれるフィールドの名前、データ型、ヘッダ、および順序に関する情報を提供します。これらの変数名は、引用符付きのコンマ区切りのリストで、データ型の形式は以下のとおりです。

ROWSPEC = "Var1:%Type1,Var2:%Type2[:OptionalDescription],Var3"

ROWSPEC は、コンマ区切りのリストとしてフィールドの順序を指定します。各フィールドの情報は、そのフィールドの名前、データ型 (対応するプロパティのデータ型と異なる場合)、およびヘッダ (オプション) をコロンで区切ったリストで構成されています。

ROWSPEC パラメータの要素数は、クエリのフィールド数と一致している必要があります。数が異なる場合、InterSystems IRIS® は “Cardinality Mismatch” エラーを返します。

例えば、Sample.Person クラスの ByName クエリは以下のようになります。

Query ByName(name As %String = "") 
    As %SQLQuery(CONTAINID = 1, ROWSPEC = "ID:%Integer,Name,DOB,SSN", SELECTMODE = "RUNTIME") 
   [ SqlName = SP_Sample_By_Name, SqlProc ]
{
        SELECT ID, Name, DOB, SSN
            FROM Sample.Person
            WHERE (Name %STARTSWITH :name)
            ORDER BY Name
}

ここでは、最初のフィールドが行 ID (既定) であることを CONTAINID パラメータで指定しています。SELECT 文で指定されている最初のフィールドも ID である点に注意してください。ROWSPEC パラメータでは、各フィールドが ID (整数として処理される)、NameDOB、および SSN であることを指定しています。同様に、SELECT 文にも IDNameDOB、および SSN の各フィールドが、この順序で含まれています。

CONTAINID パラメータ

CONTAINID は、ID を返す列の番号 (既定では 1) に設定する必要があります。ID を返す列がない場合は 0 に設定します。

Note:

システムは CONTAINID の値を検証しません。ユーザがこのパラメータに対して無効な値を指定した場合でも、エラー・メッセージは発行されません。つまり、ユーザのクエリ処理ロジックがこの情報に基づいている場合で、CONTAINID パラメータが不正に設定されているときは、不整合が生じる可能性があります。

クエリ・クラスのその他のパラメータ

ROWSPECCONTAINID に加え、以下に示すクエリのパラメータも指定できます。これらは、%SQLQueryOpens in a new tab のクラス・パラメータです。

  • SELECTMODE

  • COMPILEMODE

詳細は、%Library.SQLQueryOpens in a new tab と、そのスーパークラス %Library.QueryOpens in a new tab のクラスリファレンスを参照してください。

カスタム・クラス・クエリの定義

単純な %SQLQueryOpens in a new tab クエリは、ユーザ向けの結果セットの管理はすべて実行しますが、特定のアプリケーションにとっては十分ではありません。そのような場合、InterSystems IRIS では、カスタム・クエリを作成できます。このクエリは、メソッド内で定義します (既定では、ObjectScript で記述します)。カスタム・クエリを定義するには、この章で前述した手順を使用しますが、その手順に以下の変更を加えます。

  • クエリ・タイプには、%QueryOpens in a new tab を指定します。

  • クエリ定義の本体は空のままにしておきます。以下に例を示します。

    Query All() As %Query(CONTAINID = 1, ROWSPEC = "Title:%String,Author:%String")
    {
    }
  • 同一クラス内に、以下のクラス・メソッドを定義します。

    • querynameExecute — このメソッドでは、1 回限りの任意の設定を実行する必要があります。

    • querynameFetch — このメソッドでは、結果セットの行を返す必要があります。後続の呼び出しごとに、その次の行を返します。

    • querynameClose — このメソッドでは、クリーンアップ処理をすべて実行する必要があります。

    queryname はクエリの名前です。

    これらのメソッドは、それぞれ 1 つの引数 (qHandle) を受け入れます。この引数は、参照で渡します。この引数は、これらのメソッド間で情報を渡すために使用できます。

    これらのメソッドでクエリを定義します。詳細は、以下の各サブセクションで説明します。

基本的なデモンストレーションのために、最初の 3 つのサブセクションでは、基本クラス・クエリとして実装することも可能な簡単な例を示します。これらのメソッドは、以下のクエリのコードを実装します。

Query AllPersons() As %Query(ROWSPEC = "ID:%String,Name:%String,DOB:%String,SSN:%String")
{
}

より複雑な例は、次のセクションを参照してください。その他の使用例について、“カスタム・クエリの使用法” も参照してください。

querynameExecute() メソッドの定義

querynameExecute() メソッドでは、必要とされる設定ロジックをすべて提供する必要があります。メソッドの名前は、querynameExecute にする必要があります。queryname はクエリの名前です。このメソッドには、以下のシグニチャが必要です。

ClassMethod queryNameExecute(ByRef qHandle As %Binary, 
                             additional_arguments) As %Status

以下はその説明です。

  • qHandle は、このクエリを実装する他のメソッドとの通信に使用します。

    このメソッドでは、querynameFetch メソッドの要求に応じて、qHandle を設定する必要があります。

    qHandle は、正式には %BinaryOpens in a new tab タイプですが、任意の値 (OREF や多次元配列を含む) を保持できます。

  • additional_arguments は、クエリで使用できる任意の実行時パラメータです。

このメソッドの実装では、以下の一般的なロジックを使用します。

  1. 1 回限りの任意の設定手順を実行します。

    SQL コードを使用するクエリの場合、このメソッドには、一般的にカーソルの宣言とオープンも含めます。

  2. querynameFetch メソッドの要求に応じて、qHandle を設定します。

  3. ステータス値を返します。

次に示す単純な例は、前述の AllPersons クエリの AllPersonsExecute() メソッドです。

ClassMethod AllPersonsExecute(ByRef qHandle As %Binary) As %Status
{
    set statement=##class(%SQL.Statement).%New()
    set status=statement.%PrepareClassQuery("Sample.Person","ByName")
    if $$$ISERR(status) { quit status }
    set resultset=statement.%Execute()
    set qHandle=resultset
    Quit $$$OK
}

このシナリオでは、このメソッドで qHandle が OREF になるように設定します。具体的には、この OREF は %SQL.StatementResultOpens in a new tab のインスタンスであり、%Execute() メソッドから返された値です。

前述したように、このクラス・クエリは、カスタム・クラス・クエリではなく、基本クラス・クエリとして実装することもできます。ただし、カスタム・クラス・クエリには、開始点としてダイナミック SQL を使用するものもあります。

querynameFetch() メソッドの定義

querynameFetch() メソッドは、単一のデータ行を $List 形式で返す必要があります。メソッドの名前は、querynameFetch にする必要があります。queryname はクエリの名前です。このメソッドには、以下のシグニチャが必要です。

ClassMethod queryNameFetch(ByRef qHandle As %Binary, 
                           ByRef Row As %List,
                           ByRef AtEnd As %Integer = 0) As %Status [ PlaceAfter = querynameExecute ]

以下はその説明です。

  • qHandle は、このクエリを実装する他のメソッドとの通信に使用します。

    このメソッドの実行を InterSystems IRIS が開始するときに、qHandlequerynameExecute メソッドで設定された値か、このメソッドの前回の呼び出し (ある場合) で設定された値を保持しています。このメソッドでは、それ以降のロジックの要求に応じて、qHandle を設定する必要があります。

    qHandle は、正式には %BinaryOpens in a new tab タイプですが、任意の値 (OREF や多次元配列を含む) を保持できます。

  • Row は、返されるデータの行を表す値の %List にするか、Null 文字列 (返す値がない場合) にする必要があります。

  • AtEnd は、最後のデータの行に到達したときに 1 にする必要があります。

  • PlaceAfter メソッド・キーワードでは、生成されたルーチン・コード内で、このメソッドの位置を制御します。querynameExecute は、具体的な querynameExecute() メソッドの名前で置き換えます。これは、クエリで SQL カーソルを使用する場合には必ず含めます。(この順序を制御する機能は高度な機能であり、慎重に使用する必要があります。インターシステムズは、このキーワードの一般的な使用をお勧めしていません。)

このメソッドの実装では、以下の一般的なロジックを使用します。

  1. 返す必要のある結果が、まだあるかどうかを判断するための確認を行います。

  2. 適切な場合は、データの行を取得し、%List オブジェクトを作成して、Row 変数に格納します。

  3. qHandle は、このメソッドの以降の呼び出し (ある場合) で要求される場合や、querynameClose() メソッドで要求される場合に設定します。

  4. 以降の行が存在しない場合は、Row を Null 文字列に設定して、AtEnd を 1 に設定します。

  5. ステータス値を返します。

AllPersons の例では、AllPersonsFetch() メソッドは以下のようになります。

ClassMethod AllPersonsFetch(ByRef qHandle As %Binary, ByRef Row As %List, ByRef AtEnd As %Integer = 0) As %Status 
[ PlaceAfter = AllPersonsExecute ]
{
  set rset = $get(qHandle)
  if rset = "" quit $$$OK

  if rset.%Next() {
    set Row=$lb(rset.%GetData(1),rset.%GetData(2),rset.%GetData(3),rset.%GetData(4))
    set AtEnd=0
  } else {
    if (rset.%SQLCODE < 0) {write "%Next failed:", !, "SQLCODE ", rset.%SQLCODE, ": ", rset.%Message quit}
    set Row=""
    set AtEnd=1
  }
    quit $$$OK
}

このメソッドでは qHandle 引数を使用している点に注目してください。この引数は、%SQL.StatementResultOpens in a new tab オブジェクトを提供します。その後で、そのクラスのメソッドを使用してデータを取得しています。このメソッドでは、$List を構築して、それを Row 変数に格納しています。これは、単一のデータ行として返されます。さらに、このメソッドには、取得できるデータがなくなったときに、AtEnd 変数を設定するロジックが含まれている点にも注目してください。

前述したように、このクラス・クエリは、カスタム・クラス・クエリではなく、基本クラス・クエリとして実装することもできます。この例は、Row 変数と AtEnd 変数の設定についての実例を示すことを目的としています。

querynameClose() メソッド

querynameClose() メソッドでは、データ取得の完了後に必要になるクリーンアップをすべて実行する必要があります。メソッドの名前は、querynameClose にする必要があります。queryname はクエリの名前です。このメソッドには、以下のシグニチャが必要です。

ClassMethod queryNameClose(ByRef qHandle As %Binary) As %Status [ PlaceAfter = querynameFetch ]

以下はその説明です。

  • qHandle は、このクエリを実装する他のメソッドとの通信に使用します。

    このメソッドの実行を InterSystems IRIS が開始するときに、qHandlequerynameFetch メソッドの最後の呼び出しで設定された値を保持しています。

  • PlaceAfter メソッド・キーワードでは、生成されたルーチン・コード内で、このメソッドの位置を制御します。querynameFetch は、具体的な querynameFetch() メソッドの名前で置き換えます。これは、クエリで SQL カーソルを使用する場合には必ず含めます。(この順序を制御する機能は高度な機能であり、慎重に使用する必要があります。インターシステムズは、このキーワードの一般的な使用をお勧めしていません。)

このメソッドの実装では、メモリからの変数の削除、SQL カーソルのクローズ、またはその他のクリーンアップを必要に応じて実行します。このメソッドはステータス値を返す必要があります。

AllPersons の例では、AllPersonsClose() メソッドは以下のようになります。

例えば、ByNameClose() メソッドのシグニチャは以下のようになります。

ClassMethod AllPersonsClose(ByRef qHandle As %Binary) As %Status [ PlaceAfter = AllPersonsFetch ]
{
        Set qHandle=""
        Quit $$$OK
}

カスタム・クエリ用に生成されるメソッド

システムは、querynameGetInfo()querynameFetchRows() を自動的に生成します。ユーザのアプリケーションは、上記のメソッドを直接呼び出すことはありません。

カスタム・クエリのパラメータの定義

カスタム・クエリでパラメータを受け入れる必要がある場合は、以下の手順に従います。

  • それらをクエリ・クラス・メンバの引数リストに含めます。以下の例は、MyParm という名前のパラメータを使用しています。

    Query All(MyParm As %String) As %Query(CONTAINID = 1, ROWSPEC = "Title:%String,Author:%String")
    {
    }
  • 同じパラメータを、クエリ・クラス・メンバの順序と同じ順序で、querynameExecute メソッドの引数リストに含めます。

  • querynameExecute メソッドの実装で、必要に応じたパラメータを使用します。

Note:

ADO.NET、ODBC、または JDBC を使用してクラス・クエリを呼び出す場合、既定では、文字列パラメータが 50 文字に切り捨てられます。パラメータの最大文字列長を長くするには、以下の例のようにシグニチャで MAXLEN を指定します。

Query MyQuery(MyParm As %String(MAXLEN = 200)) As %Query [SqlProc]

管理ポータルまたは ObjectScript からクエリを呼び出す場合、この切り捨ては行われません。

カスタム・クエリを使用する場合

以下のリストでは、カスタム・クエリが適切になる、いくつかのシナリオを示しています。

  • 返されるデータに特定の行を含めるかどうかを決定するために、非常に複雑なロジックを使用する必要がある場合。querynameFetch() メソッドには、任意の複雑なロジックを含めることができます。

  • 現在の使用事例には不便な形式でデータを返す API がある場合。このようなシナリオでは、Row 変数の要求に応じて、その形式のデータを $List に変換する querynameFetch() メソッドを定義することになります。

  • クラス・インタフェースを備えていないグローバルに、データが格納されている場合。

  • データにアクセスするために、ロール・エスカレーションが必要になる場合。このシナリオでは、querynameExecute() メソッド内でロール・エスカレーションを実行します。

  • データにアクセスするために、ファイル・システムへの外部呼び出しが必要になる場合 (例えば、ファイルのリストを構築する場合)。このシナリオでは、querynameExecute() メソッド内からコールアウトを実行して、その結果を qHandle か、グローバルに格納します。

  • データを取得する前に、セキュリティ・チェック、接続のチェック、またはその他の特別な設定作業を実行する必要がある場合。そのような作業は、querynameExecute() メソッド内で実行することになります。

Note:

カスタム・クラス・クエリは、シャード・クラスではサポートされていません。

SQL カーソルとクラス・クエリ

クラス・クエリで SQL カーソルを使用する場合は、以下の点に注意してください。

  • %SQLQueryOpens in a new tab タイプのクエリから生成されたカーソルは、自動的に Q14 などの名前を持ちます。

    カーソルに固有の名前が与えられていることを確認してください。

  • エラー・メッセージは、通常、桁を 1 桁余分に持っている内部カーソル名を参照します。したがって、カーソル Q140 に対するエラー・メッセージは、おそらく Q14 を参照しています。

  • クラス・コンパイラは、カーソルを使用する前に、カーソル宣言を見つける必要があります。そのため、カーソルを使用するカスタム・クエリを定義する際には、特別な注意を払う必要があります。

    DECLARE 文 (通常は querynameExecute() メソッド内) は、Close や Fetch と同じ MAC ルーチン内にあることが必要です。また、Close や Fetch よりも先に来る必要があります。このようにするには、この章で前述したように、querynameFetch()querynameClose() の両方のメソッド定義で、メソッド・キーワード PlaceAfter を使用してください。

FeedbackOpens in a new tab