%Execute()
クエリを作成した後は、%SQL.StatementOpens in a new tab クラスの %Execute()Opens in a new tab インスタンス・メソッドを呼び出すことで、そのクエリを実行できます。SELECT 以外の文の場合は、INSERT の実行などの目的の操作を %Execute() で呼び出すことができます。SELECT クエリの場合、以降の検索とデータ取得に使用する結果セットを %Execute() で生成できます。例えば以下のようにします。
set rset = tStatement.%Execute()
%Execute() メソッドは、すべての SQL 文に対して %SQL.StatementResultOpens in a new tab クラス・プロパティ %SQLCODEOpens in a new tab および %MessageOpens in a new tab を設定します。文の実行が成功すると、%SQLCODE が 0 に設定されます。これは、文によって結果が問題なく取得されたことを示しているわけではありません。同様に、文によって結果が取得されていない場合、%Execute() では %SQLCODE が 100 に設定されません。%Next() メソッドの使用などによって一度に 1 行の結果を取得すると、結果が確認され、続いて %SQLCODE が 0、100、または負数のエラー値に設定されます。
%Execute() は、以下のようにその他の %SQL.StatementResultOpens in a new tab プロパティを設定します。
-
INSERT、UPDATE、INSERT OR UPDATE、DELETE、および TRUNCATE TABLE 文は、%ROWCOUNTOpens in a new tab を操作の影響を受ける行の数に設定します。TRUNCATE TABLE では、削除される実際の行数は特定できず、%ROWCOUNT は -1 に設定されます。
INSERT、UPDATE、INSERT OR UPDATE、および DELETE は、%ROWIDOpens in a new tab を最後に挿入、更新、または削除されたレコードの RowID 値に設定します。操作でレコードが挿入、更新、または削除されなかった場合、%ROWID は定義されないか、前の値に設定されたままになります。TRUNCATE TABLE は %ROWID を設定しません。
-
SELECT 文は、結果セットの作成時に %ROWCOUNTOpens in a new tab プロパティを 0 に設定します。%ROWCOUNT は、プログラムが結果セットのコンテンツを繰り返し処理を行うときに、(例えば %Next() メソッドを使用して) インクリメントされます。%Next() は、行上に配置されている場合は 1 を返し、最後の行の後 (結果セットの最後) に配置されている場合は 0 を返します。カーソルが最後の行の後に配置されている場合、%ROWCOUNT の値は結果セットに含まれる行数を示します。
SELECT クエリが集約関数のみを返す場合、すべての %Next() で %ROWCOUNT=1 が設定されます。最初の %Next() では、テーブルにデータがない場合でも、常に %SQLCODE=0 が設定されます。後続の %Next() では %SQLCODE=100 および %ROWCOUNT=1 が設定されます。
また、SELECT は %CurrentResultOpens in a new tab および %ResultColumnCountOpens in a new tab も設定します。SELECT は、%ROWID を設定しません。
ZWRITE を使用して、すべての %SQL.StatementResultOpens in a new tab クラス・プロパティの値を返すことができます。
詳細は、このドキュメントの “埋め込み SQL の使用法” の章の対応する SQL システム変数の説明を参照してください。%Dialect を Sybase または MSSQL に設定して TSQL コードを実行した場合、エラーはその SQL 言語の標準プロトコルと、InterSystems IRIS の %SQLCODE プロパティおよび %Message プロパティの両方で報告されます。
入力パラメータを持つ %Execute()
%Execute() メソッドは、作成された SQL 文の入力パラメータ (“?” に示される) に対応する 1 つ以上のパラメータを取得できます。%Execute() パラメータは、SQL 文内で “?” 文字が現れる順序に対応します。最初のパラメータは最初の “?” に対応し、2 番目のパラメータは、2 番目の “?” に対応し、以下同様に続きます。複数の %Execute() パラメータは、コンマで区切られます。プレースホルダとしてコンマを指定することによって、そのパラメータ値を省略できます。%Execute() パラメータの数は、“?” 入力パラメータ数と一致していなければなりません。%Execute() のパラメータの数が、対応する “?” 入力パラメータの数と一致しない場合は、%SQLCODE プロパティが SQLCODE -400 エラーに設定された状態でメソッドの実行に失敗します。
入力パラメータを使用して、リテラル値や式を SELECT リストや他のクエリ節 (TOP 節や WHERE 節など) に渡すことができます。入力パラメータを使用して、列名や列名エイリアスを SELECT リストや他のクエリ節に渡すことはできません。
明示的な %Execute() パラメータとして指定した場合の入力パラメータの最大数は 255です。可変長配列 %Execute(vals...) を使用して指定した場合の入力パラメータの最大数は 380です。
Prepare の後に、Prepare の引数メタデータを使用して、? 入力パラメータの数と必要なデータ型を返すことができます。%GetImplementationDetails() メソッドを使用して、作成済みクエリ内の ? 入力パラメータのリスト、および ? 入力パラメータをコンテキストで示したクエリ・テキストを返すことができます。
次の ObjectScript の例では、2 つの入力パラメータを持つクエリを実行します。%Execute() メソッドで入力パラメータ値 (21 と 26) を指定しています。
SET tStatement = ##class(%SQL.Statement).%New(1)
SET tStatement.%SchemaPath = "MyTests,Sample,Cinema"
SET myquery=2
SET myquery(1)="SELECT Name,DOB,Age FROM Person"
SET myquery(2)="WHERE Age > ? AND Age < ? ORDER BY Age"
SET qStatus = tStatement.%Prepare(.myquery)
IF qStatus'=1 {WRITE "%Prepare failed:" DO $System.Status.DisplayError(qStatus) QUIT}
SET rset = tStatement.%Execute(21,26)
WRITE !,"Execute OK: SQLCODE=",rset.%SQLCODE,!!
DO rset.%Display()
WRITE !,"End of data: SQLCODE=",rset.%SQLCODE
次の ObjectScript の例では、同じクエリを実行します。%Execute() メソッドの仮パラメータ・リストは、可変長配列 (dynd...) を使用して、不確定数の入力パラメータ値を指定できます。この場合は、dynd 配列の添え字です。dynd 変数は 2 に設定されていますが、これは、2 つの添え字値を示しています。
set tStatement = ##class(%SQL.Statement).%New(1)
set tStatement.%SchemaPath = "MyTests,Sample,Cinema"
set myquery=2
set myquery(1)="SELECT Name,DOB,Age FROM Person"
set myquery(2)="WHERE Age > ? AND Age < ? ORDER BY Age"
set dynd=2,dynd(1)=21,dynd(2)=26
set qStatus = tStatement.%Prepare(.myquery)
if qStatus'=1 {write "%Prepare failed:" do $System.Status.DisplayError(qStatus) quit}
set rset = tStatement.%Execute(dynd...)
write !,"Execute OK: SQLCODE=",rset.%SQLCODE,!!
do rset.%Display()
write !,"End of data: SQLCODE=",rset.%SQLCODE
作成された 1 つの結果セットに対して、複数の %Execute() 操作を発行できます。これにより、クエリを複数回、それぞれ異なる入力パラメータ値を指定して実行することが可能になります。次の例に示すように、複数の %Execute() 操作の間で結果セットを閉じる必要はありません。
set myquery="SELECT Name,SSN,Age FROM Sample.Person WHERE Name %STARTSWITH ?"
set tStatement = ##class(%SQL.Statement).%New()
set qStatus = tStatement.%Prepare(myquery)
if qStatus'=1 {write "%Prepare failed:" do $System.Status.DisplayError(qStatus) quit}
set rset = tStatement.%Execute("A")
do rset.%Display()
write !,"End of A data",!!
set rset = tStatement.%Execute("B")
do rset.%Display()
write !,"End of B data"
Try/Catch の使用による %Execute エラーの処理
TRY ブロック構造内でダイナミック SQL を実行して、関連付けられた CATCH ブロック例外ハンドラに実行時エラーを渡すことができます。%Execute() エラーの場合は、%Exception.SQLOpens in a new tab クラスを使用して例外インスタンスを作成してから、それを CATCH 例外ハンドラに THROW できます。
以下の例では、%Execute() エラーが発生したときに SQL 例外インスタンスを作成します。この場合は、? 入力パラメータの数 (1) と %Execute() のパラメータの数 (3) とでカーディナリティが一致しないというエラーが起こります。これにより、%SQLCODE プロパティと %Message プロパティの値 (Code および Data として) が CATCH 例外ハンドラにスローされます。この例外ハンドラは、%IsA() インスタンス・メソッドを使用して例外タイプをテストし、%Execute() エラーを表示します。
try {
set myquery = "SELECT TOP ? Name,DOB FROM Sample.Person"
set tStatement = ##class(%SQL.Statement).%New()
set qStatus = tStatement.%Prepare(myquery)
if qStatus'=1 {write "%Prepare failed:" do $System.Status.DisplayError(qStatus) quit}
set rset = tStatement.%Execute(7,9,4)
if rset.%SQLCODE=0 { write !,"Executed query",! }
else { set badSQL=##class(%Exception.SQL).%New(,rset.%SQLCODE,,rset.%Message)
throw badSQL }
do rset.%Display()
write !,"End of data"
return
}
catch exp { write "In the catch block",!
if 1=exp.%IsA("%Exception.SQL") {
write "SQLCODE: ",exp.Code,!
write "Message: ",exp.Data,! }
else { write "Not an SQL exception",! }
return
}
%ExecDirect()
%SQL.StatementOpens in a new tab クラスには、クエリの作成と実行の両方を単一の操作で処理する %ExecDirect()Opens in a new tab クラス・メソッドがあります。これは、指定されたクエリ (%Prepare() など) または既存のクラス・クエリ (%PrepareClassQuery() など) を作成できます。
%ExecDirect() は、指定されたクエリを作成して実行します。
set myquery=2
set myquery(1)="SELECT Name,Age FROM Sample.Person"
set myquery(2)="WHERE Age > 21 AND Age < 30 ORDER BY Age"
set rset = ##class(%SQL.Statement).%ExecDirect(,.myquery)
if rset.%SQLCODE=0 { write !,"ExecDirect OK",!! }
else { write !,"ExecDirect SQLCODE=",rset.%SQLCODE,!,rset.%Message quit}
do rset.%Display()
write !,"End of data: SQLCODE=",rset.%SQLCODE
%ExecDirect() は、既存のクラス・クエリを作成して実行します。
set mycallq = "?=CALL Sample.PersonSets('A','NH')"
set rset = ##class(%SQL.Statement).%ExecDirect(,mycallq)
if rset.%SQLCODE=0 { write !,"ExecDirect OK",!! }
else { write !,"ExecDirect SQLCODE=",rset.%SQLCODE,!,rset.%Message quit}
do rset.%Display()
write !,"End of data: SQLCODE=",rset.%SQLCODE
次の例に示すように、%ExecDirect() クラス・メソッドの 3 番目以降のパラメータとして入力パラメータの値を指定できます。
set myquery=2
set myquery(1)="SELECT Name,Age FROM Sample.Person"
set myquery(2)="WHERE Age > ? AND Age < ? ORDER BY Age"
set rset = ##class(%SQL.Statement).%ExecDirect(,.myquery,12,20)
if rset.%SQLCODE'=0 {write !,"1st ExecDirect SQLCODE=",rset.%SQLCODE,!,rset.%Message quit}
do rset.%Display()
write !,"End of teen data",!!
set rset2 = ##class(%SQL.Statement).%ExecDirect(,.myquery,19,30)
if rset2.%SQLCODE'=0 {write !,"2nd ExecDirect SQLCODE=",rset2.%SQLCODE,!,rset2.%Message quit}
do rset2.%Display()
write !,"End of twenties data"
%ExecDirect() の入力パラメータは、SQL 文内で “?” 文字が現れる順序に対応します。すなわち、3 番目のパラメータは最初の “?” に対応し、4 番目のパラメータは、2 番目の “?” に対応し、以下同様に続きます。プレースホルダとしてコンマを指定することによって、そのパラメータ値を省略できます。%ExecDirect() の入力パラメータの数が、対応する “?” 入力パラメータの数より少ない場合、既定値が存在すればその既定値が使用されます。
次の例では、最初の %ExecDirect() では、3 つの “?” 入力パラメータのすべてを指定しています。2 番目の %ExecDirect() では、2 番目の ? 入力パラメータのみを指定し、1 番目と 3 番目のパラメータは省略しています。3 番目の入力パラメータには、Sample.PersonSets() の既定値 ('MA') が使用されます。
set mycall = "?=CALL Sample.PersonSets(?,?)"
set rset = ##class(%SQL.Statement).%ExecDirect(,mycall,"","A","NH")
if rset.%SQLCODE'=0 {write !,"1st ExecDirect SQLCODE=",rset.%SQLCODE,!,rset.%Message quit}
do rset.%Display()
write !,"End of A people data",!!
set rset2 = ##class(%SQL.Statement).%ExecDirect(,mycall,,"B")
if rset2.%SQLCODE'=0 {write !,"2nd ExecDirect SQLCODE=",rset2.%SQLCODE,!,rset2.%Message quit}
do rset2.%Display()
write !,"End of B people data"
%ExecDirect() は、%SQL.StatementOpens in a new tab の %Display()Opens in a new tab インスタンス・メソッドまたは %GetImplementationDetails()Opens in a new tab インスタンス・メソッドを呼び出して、現在作成されている文の詳細を返すことができます。%ExecDirect() は、指定クエリでも既存のクラス・クエリでも作成して実行できるため、作成されているクエリの種類を判別するには、%GetImplementationDetails() の pStatementType パラメータを使用できます。
set mycall = "?=CALL Sample.PersonSets('A',?)"
set rset = ##class(%SQL.Statement).%ExecDirect(tStatement,mycall,,"NH")
if rset.%SQLCODE'=0 {write !,"ExecDirect SQLCODE=",rset.%SQLCODE,!,rset.%Message quit}
set bool = tStatement.%GetImplementationDetails(.pclassname,.ptext,.pargs,.pStatementType)
if bool=1 {if pStatementType=1 {write "Type= specified query",!}
elseif pStatementType=45 {write "Type= existing class query",!}
write "Implementation class= ",pclassname,!
write "Statement text= ",ptext,!
write "Arguments= ",$listtostring(pargs),!! }
else {write "%GetImplementationDetails() failed"}
do rset.%Display()
write !,"End of data"
詳細は、"正常な作成の結果" を参照してください。