問合せの使用

Oracle NoSQL Databaseのアプリケーションに対して問合せを使用することについて学習します。

Oracle NoSQL Databaseには、データの読取りおよび更新のための豊富な問合せ言語が用意されています。問合せ言語の詳細は、開発者ガイドを参照してください。

問合せを実行するには、NoSQLHandle.query() APIを使用します。

SELECT問合せを実行して表からデータを読み取るには、次のステップを実行します。
/* QUERY a table named "users", using the primary key field "name". 
 * The table name is inferred from the query statement.
 */
QueryRequest queryRequest = new QueryRequest().
setStatement("SELECT * FROM users WHERE name = \"Taylor\"");

/* Queries can return partial results. It is necessary to loop,
 * reissuing the request until it is "done"
 */

do {
  QueryResult queryResult = handle.query(queryRequest);

  /* process current set of results */
  List<MapValue> results = queryResult.getResults();
  for (MapValue qval : results) {
    //handle result
  }
} while (!queryRequest.isDone());

問合せを使用するときには、次の考慮事項に注意してください。

  • 同じ問合せを複数回実行する場合は、準備された問合せを使用できます。準備された問合せを使用すると、問合せ文字列を毎回開始するよりも実行の効率が上がります。問合せ言語およびAPIは、再利用に役立つ問合せ変数をサポートしています。

たとえば、準備された文を使用して、SELECT問合せを実行し、表からデータを読み取る場合は、次のようになります。

/* Perform the same query using a prepared statement. This is more
 * efficient if the query is executed repeatedly and required if
 * the query contains any bind variables.
 */
String query = "DECLARE $name STRING; " +
               "SELECT * from users WHERE name = $name";

PrepareRequest prepReq = new PrepareRequest().setStatement(query);
/* prepare the statement */
PrepareResult prepRes = handle.prepare(prepReq);
/* set the bind variable and set the statement in the QueryRequest */
prepRes.getPreparedStatement()
       .setVariable("$name", new StringValue("Taylor"));
QueryRequest queryRequest = new QueryRequest().setPreparedStatement(prepRes);

/* perform the query in a loop until done */
do {
  QueryResult queryResult = handle.query(queryRequest);
  /* handle result */
} while (!queryRequest.isDone());
問合せを実行するには、borneo.NoSQLHandle.query()メソッドを使用します。たとえば、SELECT問合せを実行して表からデータを読み取る場合、borneo.QueryResultには結果のリストが含まれています。また、borneo.QueryRequest.is_done()がFalseを返す場合、結果がより多くなる可能性があるため、通常、問合せはループで実行する必要があります。単一のリクエストでは結果が返されない可能性があり、問合せがまだ実行されないため、問合せループを続行する必要があることを示します。たとえば:
from borneo import QueryRequest
# Query at table named 'users" using the field 'name' where name may match 
# 0 or more rows in the table. The table name is inferred from the query 
statement = 'select * from users where name = "Jane"'
request = QueryRequest().set_statement(statement) 
# loop until request is done, handling results as they arrive
while True: result = handle.query(request)
# handle results
handle_results(result)
# do something with results
if request.is_done(): break
問合せを使用する際には、次の考慮事項に注意することが重要です。
  • Oracle NoSQL Databaseには、実行および再利用のための問合せを準備する機能があります。同じ問合せを複数回実行する場合は、準備した問合せを使用することをお薦めします。準備された問合せを使用すると、問合せ文字列を毎回開始するよりも実行の効率が上がります。問合せ言語およびAPIは、問合せの再利用に役立つ問合せ変数をサポートしています。
  • borneo.QueryRequestを使用すると、問合せの読取り整合性を設定したり、単一のリクエストで使用されるリソース(読取りおよび書込み)の最大量を変更できます。あまりにも多くのリソースがあまりにも早く使用されるため、問合せが調整されないようにすることが重要です。
1つの変数で準備された問合せを使用する例を次に示します。
from borneo import PrepareRequest, QueryRequest
# Use a similar query to above but make the name a variable
statement = 'declare $name string
select * from users where name = $name'
prequest = PrepareRequest().set_statement(statement)
presult = handle.prepare(prequest)
# use the prepared statement, set the variable 
pstatement = presult.get_prepared_statement()
pstatement.set_variable('$name', 'Jane')
qrequest = QueryRequest().set_prepared_statement(pstatement)
# loop until qrequest is done, handling results as they arrive
while True:
# use the prepared query in the query 
request qresult = handle.query(qrequest)
# handle results
handle_results(qresult)
# do something with results
if qrequest.is_done(): break
# use a different variable value with the same prepared query
pstatement.set_variable('$name', 'another_name') 
qrequest = QueryRequest().set_prepared_statement(pstatement)
# loop until qrequest is done, handling results as they arrive
while True:
# use the prepared query in the query 
request qresult = handle.query(qrequest)
# handle results
handle_results(qresult)
# do something with results
if qrequest.is_done(): break
問合せを実行するには、Client.Query関数を使用します。たとえば、SELECT問合せを実行して表からデータを読み取る場合:
prepReq := &nosqldb.PrepareRequest{
    Statement: "select * from users",
}
prepRes, err := client.Prepare(prepReq)
if err != nil {
    fmt.Printf("Prepare failed: %v\n", err)
    return
}
queryReq := &nosqldb.QueryRequest{
    PreparedStatement: &prepRes.PreparedStatement,
}
var results []*types.MapValue
for {
    queryRes, err := client.Query(queryReq)
    if err != nil {
        fmt.Printf("Query failed: %v\n", err)
        return
    }
    res, err := queryRes.GetResults()
    if err != nil {
        fmt.Printf("GetResults() failed: %v\n", err)
        return
    }
    results = append(results, res...)
    if queryReq.IsDone() {
        break
    }
}

通常、問合せはループで実行し、QueryRequest.IsDone()をチェックして問合せが完了したかどうかを判断します。1つのリクエストで結果を返さず、QueryRequest.IsDone()がfalseに評価される可能性があり、問合せループが続行される必要があることを示します。

問合せを使用する際には、次の考慮事項に注意することが重要です。
  • Oracle NoSQL Databaseには、実行および再利用のための問合せを準備する機能があります。同じ問合せを複数回実行する場合は、準備した問合せを使用することをお薦めします。準備された問合せを使用すると、問合せ文字列を毎回開始するよりも実行の効率が上がります。問合せ言語およびAPIは、問合せの再利用に役立つ問合せ変数をサポートしています。
  • nosqldb.QueryRequestを使用すると、(QueryRequest.Consistencyフィールドを介して)問合せの読取り整合性を設定したり、単一リクエストで使用されるリソースの最大量を変更できます(QueryRequest.MaxReadKBおよびQueryRequest.MaxWriteKBフィールドを介して読取りおよび書込みを実行します)。あまりにも多くのリソースがあまりにも早く使用されるため、問合せが調整されないようにすることが重要です。
問合せを実行するには、queryメソッドを使用します。このメソッドは、結果の行の配列および継続キーを含むプレーンJavaScriptオブジェクトであるQueryResultPromiseを返します。問合せによって返されるデータの量はシステム・デフォルトによって制限され、queryのopt引数にmaxReadKBプロパティを設定することでさらに制限できます。これは、queryメソッドの1回の呼出しでは、使用可能なすべての結果が返されない可能性があることを意味します。この状況は、continuationKeyプロパティを使用して処理されます。nullでない継続キーは、より多くの問合せ結果を使用できることを意味します。つまり、通常、問合せはループで実行される必要があり、継続キーがnullになるまでループされます。行が空になる可能性があり、continuationKeyがnullでないことに注意してください。これは、問合せループを続行する必要があることを意味します。すべての結果を受信するには、ループでqueryをコールします。反復のたびに、QueryResultでnull以外の継続キーが受信された場合は、次の反復のopt引数にcontinuationKeyプロパティを設定します。
const NoSQLClient = require('oracle-nosqldb').NoSQLClient;
.....
const client = new NoSQLClient('config.json');
async function queryUsersTable() {
    const opt = {};
    try {
        do {
            const result = await client.query('SELECT * FROM users', opt);
            for(let row of result.rows) {
                console.log(row);
            }
            opt.continuationKey = result.continuationKey;
        } while(opt.continuationKey);
    } catch(error) {
        //handle errors
    }
}
問合せを使用する際には、次の考慮事項に注意することが重要です。
  • Oracle NoSQL Databaseには、実行および再利用のための問合せを準備する機能があります。同じ問合せを複数回実行する場合は、準備した問合せを使用することをお薦めします。準備された問合せを使用すると、問合せ文字列を毎回開始するよりも実行の効率が上がります。問合せ言語およびAPIは、問合せの再利用に役立つ問合せ変数をサポートしています。
  • queryのopt引数を使用すると、問合せの読取り整合性を設定し、1回のコールで読み取るデータの最大量を変更できます。これは、問合せが調整されないようにするために重要です。
問合せを準備するには、prepareメソッドを使用します。このメソッドは、PreparedStatementオブジェクトのPromiseを返します。setメソッドを使用して、問合せ変数をバインドします。準備済問合せを実行するには、問合せにPreparedStatementを渡すか、文の文字列のかわりにqueryIterableを渡します。
const NoSQLClient = require('oracle-nosqldb').NoSQLClient;
.....
const client = new NoSQLClient('config.json');

async function queryUsersTable() {
    const statement = 'DECLARE $name STRING; SELECT * FROM users WHERE ' +
        'name = $name';
    try {
        let prepStatement = await client.prepare(statement);
        const opt = {};
        // Set value for $name variable
        prepStatement.set('$name', 'Taylor');
        do {
            let result = await client.query(prepStatement);
            for(let row of result.rows) {
                console.log(row);
            }
           opt.continuationKey = result.continuationKey;
        } while (opt.continuationKey);
        // Set different value for $name and re-execute the query
        prepStatement.set('$name', 'Jane');
        do {
            let result = await client.query(prepStatement);
            for(let row of result.rows) {
                console.log(row);
            }
           opt.continuationKey = result.continuationKey;
        } while (opt.continuationKey);
    } catch(error) {
        //handle errors
    }
}
問合せを実行するには、QueryAsyncメソッドをコールするか、GetQueryAsyncEnumerableメソッドをコールして、結果の非同期列挙可能性に対して反復処理します。これらの各メソッドにQueryOptionsとしてオプションを渡すことができます。QueryAsyncメソッドはTask<QueryResult<RecordValue>>を返します。QueryResultには、RecordValueインスタンスのリストおよびその他の情報として問合せ結果が含まれています。問合せで完全な主キーが指定されている場合(またはINSERT文を実行している場合)、QueryAsyncを1回コールすれば十分です。
var client = new NoSQLClient("config.json");
try {
    var result = await client.QueryAsync(
    "SELECT * FROM users WHERE id = 1");
    // Because we select by primary key, there can be at most one record.
    if (result.Rows.Count>0) {
       Console.WriteLine("Got record: {0}.", result.Rows[0]);
    }
    else {
       Console.WriteLine("Got no records.");
    }
}
catch(Exception ex) {
  // handle exceptions
}

問合せによって返されるデータ量は、システムによって制限されます。また、QueryOptionsMaxReadKBプロパティを設定して、さらに制限することもできます。つまり、QueryAsyncを1回起動しても、使用可能なすべての結果が返されるわけではありません。この状況は、継続キーを使用して処理されます。QueryResultのnull以外のContinuationKeyは、より多くの問合せ結果を使用できることを意味します。つまり、通常、問合せはループで実行される必要があり、継続キーがnullになるまでループされます。

問合せで現在行(QueryResult.Rowsは空)が返され、nullでない継続キーを持つ可能性があることに注意してください。つまり、問合せはループを続行する必要があることを意味します。問合せを続行するには、QueryAsyncへの次のコールのためにQueryOptionsContinuationKeyを設定し、継続キーがnullになるまでループします。次の例では、問合せが実行され、問合せ結果が出力されます。
var client = new NoSQLClient("config.json");
var options = new QueryOptions();
try {
    do {
        var result = await client.QueryAsync(
            "SELECT id, name FROM users ORDER BY name",
            options);
        foreach(var row of result.Rows) {
            Console.WriteLine(row);
        }
        options.ContinuationKey = result.ContinuationKey;
    }
    while(options.ContinuationKey != null);
}
catch(Exception ex){
    // handle exceptions
}
ループで問合せを実行する別の方法は、GetQueryAsyncEnumerableを使用することです。反復可能なAsyncEnumerable<QueryResult>のインスタンスを返します。各反復ステップでは、問合せ結果の一部がQueryResultとして返されます。
var client = new NoSQLClient("config.json");
try {
    await foreach(var result in client.GetQueryAsyncEnumerable(
        "SELECT id, name FROM users ORDER BY name"))
    {
        foreach(var row of result.Rows) {
            Console.WriteLine(row);
        }
    }
}
catch(Exception ex){
    // handle exceptions
}

Oracle NoSQL Databaseには、実行および再利用のための問合せを準備する機能があります。同じ問合せを複数回実行する場合は、準備した問合せを使用することをお薦めします。準備された問合せを使用すると、SQL文を毎回開始するよりも実行の効率が上がります。問合せ言語およびAPIは、問合せの再利用に役立つ問合せ変数をサポートしています。

PrepareAsyncを使用して問合せを準備します。このメソッドはTask<PreparedStatement>を返します。PreparedStatementを使用すると、問合せ変数を設定できます。問合せメソッドQueryAsyncおよびGetQueryAsyncEnumerableには、SQL文のかわりにPreparedStatementをパラメータとして取得することによって準備済問合せを実行するオーバーロードがあります。たとえば:
var client = new NoSQLClient("config.json");
try {
    var sql = "DECLARE $name STRING; SELECT * FROM users WHERE " +
        "name = $name";
    var preparedStatement = await client.PrepareAsync(sql);
    // Set value for $name variable and execute the query
    preparedStatement.Variables["$name"] = "Taylor";
    await foreach(var result in client.GetQueryAsyncEnumerable(
        preparedStatement)) {
        foreach(var row of result.Rows) {
            Console.WriteLine(row);
        }
    }
    // Set different value for $name and re-execute the query.
    preparedStatement.Variables["$name"] = "Jane";
    await foreach(var result in client.GetQueryAsyncEnumerable(
        preparedStatement)) {
        foreach(var row of result.Rows) {
            Console.WriteLine(row);
        }
    }
}
catch(Exception ex){
    // handle exceptions
}
次のいずれかの方法を使用して、問合せを実行します。NosqlRepository導出問合せ、ネイティブ問合せ、またはNosqlTemplate runQuery()runQueryJavaParams()runQueryNosqlParams()を使用します。詳細は、SDK for Spring Data APIリファレンスを参照してください。

ノート:

まず、Oracle NoSQL Databaseの接続詳細を指定するために、AbstractNosqlConfigurationクラスを拡張するAppConfigクラスを作成します。詳細は、「NoSQL接続の取得」を参照してください。

この項では、導出問合せを使用します。導出問合せの詳細は、Spring Data SDK開発者ガイド導出問合せを参照してください。

UsersRepositoryインタフェースを作成します。このインタフェースは、NosqlRepositoryインタフェースを拡張して、そのクラスの主キーのエンティティ・クラスとデータ型をパラメータ化された型としてNosqlRepositoryインタフェースに提供します。NosqlRepositoryインタフェースは、データベースからデータを取得するために使用されるメソッドを備えています。
import com.oracle.nosql.spring.data.repository.NosqlRepository;
 
/* The Users is the entity class and Long is the data type of the primary key in the Users class.
   This interface provides methods that return iterable instances of the Users class. */
 
public interface UsersRepository extends NosqlRepository<Users, Long> {
    /* Search the Users table by the last name and return an iterable instance of the Users class.*/
    Iterable<Users> findByLastName(String lastname);
}
アプリケーションでは、必要に応じて姓を使用してUsers表から行を選択し、オブジェクトからの出力にこの値を出力します。
@Autowired
private UsersRepository repo;
 
System.out.println("\nfindBylastName: Willard");
 
/* Use queries to find by the last Name. Search the Users table by the last name and return an iterable instance of the Users class.*/
allusers = repo.findByLastName("Willard");
 
for (Users s: allusers) {
    System.out.println(" User: " + s);
}
プログラムを実行して出力を表示します。
findBylastName: Willard

User: Users{id=2, firstName=Angela, lastName=Willard}