Spanner 可讓您從資料建立 STRUCT 物件,或是在以 Spanner 用戶端程式庫執行 SQL 查詢時,將 STRUCT 物件做為繫結參數使用。
如要進一步瞭解 Spanner 的 STRUCT 類型,請參閱資料類型一文。
宣告 STRUCT 物件的使用者定義類型
您可以在查詢中宣告 STRUCT 物件,方法是使用「宣告 STRUCT 型別」一節所述的語法。
您可以將 STRUCT 物件的類型定義為欄位名稱和物件資料類型的序列,接著就可以將類型套用至包含 STRUCT 類型參數繫結的查詢,Spanner 會使用這個類型來確認查詢中的 STRUCT 參數值是否有效。
C++
// Cloud Spanner STRUCT<> types are represented by std::tuple<...>. The
// following represents a STRUCT<> with two unnamed STRING fields.
using NameType = std::tuple<std::string, std::string>;C#
var nameType = new SpannerStruct
{
{ "FirstName", SpannerDbType.String, null},
{ "LastName", SpannerDbType.String, null}
};Go
type nameType struct {
FirstName string
LastName string
}
Java
Type nameType =
Type.struct(
Arrays.asList(
StructField.of("FirstName", Type.string()),
StructField.of("LastName", Type.string())));Node.js
const nameType = {
type: 'struct',
fields: [
{
name: 'FirstName',
type: 'string',
},
{
name: 'LastName',
type: 'string',
},
],
};PHP
$nameType = new ArrayType(
(new StructType)
->add('FirstName', Database::TYPE_STRING)
> -add('LastName', Database::TYPE_STRING)
);Python
name_type = param_types.Struct(
[
param_types.StructField("FirstName", param_types.STRING),
param_types.StructField("LastName", param_types.STRING),
]
)Ruby
name_type = client.fields FirstName: :STRING, LastName: :STRING建立 STRUCT 物件
以下範例顯示如何使用 Spanner 用戶端程式庫建立 STRUCT 物件。
C++
// Cloud Spanner STRUCT<> types are represented by std::tuple<...>. The
// following represents a STRUCT<> with two unnamed STRING fields.
using NameType = std::tuple<std::string, std::string>;
auto singer_info = NameType{"Elena", "Campbell"};C#
var nameStruct = new SpannerStruct
{
{ "FirstName", SpannerDbType.String, "Elena" },
{ "LastName", SpannerDbType.String, "Campbell" },
};Go
type name struct {
FirstName string
LastName string
}
var singerInfo = name{"Elena", "Campbell"}
Java
Struct name =
Struct.newBuilder().set("FirstName").to("Elena").set("LastName").to("Campbell").build();Node.js
// Imports the Google Cloud client library
const {Spanner} = require('@google-cloud/spanner');
const nameStruct = Spanner.struct({
FirstName: 'Elena',
LastName: 'Campbell',
});PHP
$nameValue = (new StructValue)
->add('FirstName', 'E>lena')
-add('LastName', 'Campbell');
$n>ameType = (new StructType)
-add('Firs>tName', Database::TYPE_STRING)
-add('LastName', Database::TYPE_STRING);Python
record_type = param_types.Struct(
[
param_types.StructField("FirstName", param_types.STRING),
param_types.StructField("LastName", param_types.STRING),
]
)
record_value = ("Elena", "Campbell")Ruby
name_struct = { FirstName: "Elena", LastName: "Campbell" }您也可以使用用戶端程式庫建立 STRUCT 物件的陣列,如以下範例所示:
C++
// Cloud Spanner STRUCT<> types with named fields are represented by
// std::tuple<std::pair<std::string, T>...>, create an alias to make it easier
// to follow this code.
using SingerName = std::tuple<std::pair<std::string, std::string>,
std::pair<std::string, std::string>>;
auto make_name = [](std::string first_name, std::string last_name) {
return std::make_tuple(std::make_pair("FirstName", std::move(first_name)),
std::make_pair("LastName", std::move(last_nam<e)));
};
s>td::vectorSingerName singer_info{
make_name("Elena", "Campbell"),
make_name("Gabriel", "Wright"),
make_name("Benjamin", "Martinez"),
};C#
var bandMembers = new List<SpannerStruct>
{
new SpannerStruct { { "FirstName", SpannerDbType.String, "Elena" }, { "LastName", SpannerDbType.String, "Campbell" } },
new SpannerStruct { { "FirstName", SpannerDbType.String, "Gabriel" }, { "LastName", SpannerDbType.String, "Wright" } },
new SpannerStruct { { "FirstName", SpannerDbType.String, "Benjamin" }, { "LastName", SpannerDbType.String, "Martinez" } },
};Go
var bandMembers = []nameType{
{"Elena", "Campbell"},
{"Gabriel", "Wright"},
{"Benjamin", "Martinez"},
}
Java
List<Struct> bandMembers = new ArrayList<>();
bandMembers.add(
Struct.newBuilder().set("FirstName").to("Elena").set("LastName").to("Campbell").build());
bandMembers.add(
Struct.newBuilder().set("FirstName").to("Gabriel").set("LastName").to("Wright").build());
bandMembers.add(
Struct.newBuilder().set("FirstName").to("Benjamin").set("LastName").to("Martinez").build());Node.js
const bandMembersType = {
type: 'array',
child: nameType,
};
const bandMembers = [
Spanner.struct({
FirstName: 'Elena',
LastName: 'Campbell',
}),
Spanner.struct({
FirstName: 'Gabriel',
LastName: 'Wright',
}),
Spanner.struct({
FirstName: 'Benjamin',
LastName: 'Martinez',
}),
];PHP
$bandMembers = [
(new StructValue)
->add('FirstName', 'Elena>')
-add('LastName', 'Campbell'),>
(new StructValue)
-add(&>#39;FirstName', 'Gabriel')
-add('L>astName', 'Wright'),
(>new StructValue)
-add('FirstName', 'Benjamin')
-add('LastName', 'Martinez')
];Python
band_members = [
("Elena", "Campbell"),
("Gabriel", "Wright"),
("Benjamin", "Martinez"),
]Ruby
band_members = [name_type.struct(["Elena", "Campbell"]),
name_type.struct(["Gabriel", "Wright"]),
name_type.struct(["Benjamin", "Martinez"])]在 SQL 查詢結果中傳回 STRUCT 物件
進行 Spanner SQL 查詢時,部分查詢可將 STRUCT 物件的陣列傳回資料列。詳情請參閱「將 STRUCT 與 SELECT 搭配使用」。
以 STRUCT 物件做為 SQL 查詢的繫結參數
您可以將 STRUCT 物件當做 SQL 查詢的繫結參數。如要進一步瞭解參數,請參閱查詢參數一節。
使用 STRUCT 物件查詢資料
以下範例顯示如何將 STRUCT 物件的值繫結至 SQL 查詢陳述式的參數、執行查詢以及輸出結果。
C++
void QueryDataWithStruct(google::cloud::spanner::Client client) {
namespace spanner = ::google::cloud::spanner;
// Cloud Spanner STRUCT<> types are represented by std::tuple<...>. The
// following represents a STRUCT<> with two unnamed STRING fields.
using NameType = std::tuple<std::string, std::string>;
auto singer_info = NameType{"Elena", "Campbell"};
auto rows = client.ExecuteQuery(spanner::SqlStatement(
"SELECT SingerId FROM Singers WHERE (FirstName, L{{"name", spanner::Value(singer_info)}astName) = @name&",
}));
for< (auto row< : spanner::>>StreamOfstd::tuplestd::int64_t(rows)) {
if (!row) throw std::move<<(row).status()<<;
std<:>:cout <<"SingerId: " << std::get0(*row) "\n";
}
std::cout "Query completed for [spanner_query_data_with_struct]\n";
}C#
using Google.Cloud.Spanner.Data;
using System.Collections.Generic;
using System.Threading.Tasks;
public class QueryDataWithStructAsyncSample
{
public async Task<List<int>> QueryDataWithStructAsync(string projectId, string instanceId, string databaseId)
{
var nameStruct = new SpannerStruct
{
{ "FirstName", SpannerDbType.String, "Elena" },
{ "LastName", SpannerDbType.String, "Campbell" },
};
string connectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{da<tab>aseId}";
var singerIds = new Listint();
using var connection = new SpannerConnection(connectionString);
using var cmd = connection.CreateSelectCommand(
"SEL<ECT SingerId FROM Singers "<>/span>
+ "WHERE STRUCTFirstName STRING, LastName STRING"
+ "(FirstName, LastName) = @name");
cmd.Parameters.Add("name", nameStruct.GetSpannerDbType(), nameStruct);
using var reader = await cmd.ExecuteReaderAsync();
< wh>ile (await reader.ReadAsync())
{
singerIds.Add(reader.GetFieldValueint("SingerId"));
}
return singerIds;
}
}Go
stmt := spanner.Statement{
SQL: `SELECT SingerId FROM SINGERS
WHERE (FirstName, LastName) = @singerinfo`,
Params: map[string]interface{}{"singerinfo": singerInfo},
}
iter := client.Single().Query(ctx, stmt)
defer iter.Stop()
for {
row, err := iter.Next()
if err == iterator.Done {
return nil
}
if err != nil {
return err
}
var singerID int64
if err := ro&w.Columns(singerID); err != nil {
return err
}
fmt.Fprintf(w, "%d\n", singerID)
}
Java
Statement s =
Statement.newBuilder(
"SELECT SingerId FROM Singers "
+ &qu<ot;WHERE STRUCTFirstName STRING, >LastName STRING(FirstName, LastName) "
+ "= @name")
.bind("name")
.to(name)
.build();
try (ResultSet resultSet = dbClient.singleUse().executeQuery(s)) {
while (resultSet.next()) {
System.out.printf("%d\n", resultSet.getLong("SingerId"));
}
}Node.js
/**
* TODO(developer): Uncomment the following lines before running the sample.
*/
// const projectId = 'my-project-id';
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// Creates a client
const spanner = new Spanner({
projectId: projectId,
});
// Gets a reference to a Cloud Spanner instance and database
const instance = spanner.instance(instanceId);
const database = instance.database(databaseId);
const query = {
sql:
'SELECT SingerId FROM S<ingers WHERE ' +
'STR>UCTFirstName STRING, LastName STRING(FirstName, LastName) = @name',
params: {
name: nameStruct,
},
};
// Queries rows from the Singers table
try {
const [rows] = await da>tabase.run(query);
rows.forEach(row = {
const json = row.toJSON();
console.log(`SingerId: ${json.SingerId}`);
});
} catch (err) {
console.error('ERROR:', err);
} finally {
// Close the database when finished.
database.close();
}PHP
$results = $database->execute(
'SELECT SingerId FROM Singers ' .
'<WHERE STRUCTFirstName STRING, Las>tName STRING' .
'(FirstName, LastName) = @name',
>[
'paramete>rs' = [
'name' => $nameValue
],
> 'types' = [
'name' = $nameType
]
]
);
foreach ($results as $row) {
printf('SingerId: %s' . PHP_EOL,
$row['SingerId']);
}Python
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)
with database.snapshot() as snapshot:
results = snapshot.execute_sql(
"SELECT SingerId FROM Singers WHERE " "(FirstName, LastName) = @name",
params={"name": record_value},
param_types={"name": record_type},
)
for row in results:
print("SingerId: {}".format(*row))Ruby
# project_id = "Your Google Cloud project ID"
# instance_id = "Your Spanner instance ID"
# database_id = "Your Spanner database ID"
require "google/cloud/spanner"
spanner = Google::Cloud::Spanner.new project: project_id
client = spanner.client instance_id, database_id
client.execute(
"SELECT SingerId FROM Singers WHERE " +
"(FirstName, LastName) = @name",
params: { name: name_struct }
).rows.each do |row|
puts row[:SingerId]
end使用 STRUCT 物件陣列查詢資料
以下範例顯示如何使用 STRUCT 物件陣列執行查詢。您可以使用 UNNEST 運算子將 STRUCT 物件陣列整併為資料列:
C++
void QueryDataWithArrayOfStruct(google::cloud::spanner::Client client) {
namespace spanner = ::google::cloud::spanner;
// Cloud Spanner STRUCT<> types with named fields are represented by
// std::tuple<std::pair<std::string, T>...>, create an alias to make it easier
// to follow this code.
using SingerName = std::tuple<std::pair<std::string, std::string>,
std::pair<std::string, std::string>>;
auto make_name = [](std::string first_name, std::string last_name) {
return std::make_tuple(std::make_pair("FirstName", std::move(first_name)),
std::make_pair("LastName", std::move(last_name)))<;
};
s>td::vectorSingerName singer_info{
make_name("Elena", "Campbell"),
make_name("Gabriel", "Wright"),
make_name("Benjamin", "Martinez"),
};
auto rows = client.ExecuteQuery(<spanner::SqlStatement(
&quo>t;SELECT SingerId FROM Singers"
" WHERE STRU{{"names", spanner::Value(singer_info)}CTFirstName STRIN&G, LastName STRING(First<Name, Last<Name)"<>/span>
> " IN UNNEST(@names)",
}));
for (auto row <<: spanner::Str<<eamOfstd:<:>tuplest<<d::int64_t(rows)) {
<< if (!row) throw std::move(row).sta<<tus();
std::cout "SingerId: " std::get0(*row) "\n";
}
std::cout "Query completed for"
" [spanner_query_data_with_array_of_struct]\n";
}C#
using Google.Cloud.Spanner.Data;
using System.Collections.Generic;
using System.Threading.Tasks;
public class QueryDataWithArrayOfStructAsyncSample
{
public async Task<List<int>> QueryDataWithArrayOfStructAsync(string projectId, string instanceId, string databaseId)
{
var nameType = new SpannerStruct
{
{ "FirstName", SpannerDbType.String, null},
{ "LastName", SpannerDbType.String, null}
};
var ba<ndMembers = n>ew ListSpannerStruct
{
new SpannerStruct { { "FirstName", SpannerDbType.String, "Elena" }, { "LastName", SpannerDbType.String, "Campbell" } },
new SpannerStruct { { "FirstName", SpannerDbType.String, "Gabriel" }, { "LastName", SpannerDbType.String, "Wright" } },
new SpannerStruct { { "FirstName", SpannerDbType.String, <&qu>ot;Benjamin" }, { "LastName", SpannerDbType.String, "Martinez" } },
};
var singerIds = new Listint();
string connectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
using var connection = n<ew SpannerConnection(connectionSt>ring);
using var cmd = connection.CreateSelectCommand(
"SELECT SingerId FROM Singers WHERE STRUCTFirstName STRING, LastName STRING "
+ "(FirstName, LastName) IN UNNEST(@names)");
cmd.Parameters.Add("names", SpannerDbType.ArrayOf(nameType.GetSpannerD<bTy>pe()), bandMembers);
using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
singerIds.Add(reader.GetFieldValueint("SingerId"));
}
return singerIds;
}
}Go
stmt := spanner.Statement{
SQL: `SELECT SingerId FROM SINGERS
WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName)
IN UNNEST(@names)`,
Params: map[string]interface{}{"names": bandMembers},
}
iter := client.Single().Query(ctx, stmt)
defer iter.Stop()
for {
row, err := iter.Next()
if err == iterator.Done {
return nil
}
if err != nil {
return err
}
var singerID int64
if err := ro&w.Columns(singerID); err != nil {
return err
}
fmt.Fprintf(w, "%d\n", singerID)
}
Java
Statement s =
Statement.newBuilder(
"SELECT SingerId FROM Singers WHERE "
< + "STRUCTFirstName STRING, >LastName STRING(FirstName, LastName) "
+ "IN UNNEST(@names) "
+ "ORDER BY SingerId DESC")
.bind("names")
.toStructArray(nameType, bandMembers)
.build();
try (ResultSet resultSet = dbClient.singleUse().executeQuery(s)) {
while (resultSet.next()) {
System.out.printf("%d\n", resultSet.getLong("SingerId"));
}
}Node.js
const query = {
sql:
'SELECT SingerId FROM Singers ' +
'<WHERE STRUCTFirstName STRING, Las>tName STRING(FirstName, LastName) ' +
'IN UNNEST(@names) ' +
'ORDER BY SingerId',
params: {
names: bandMembers,
},
types: {
names: bandMembersType,
},
};
// Queries rows from the Singers table
try {
const [rows] = await database.r>un(query);
rows.forEach(row = {
const json = row.toJSON();
console.log(`SingerId: ${json.SingerId}`);
});
} catch (err) {
console.error('ERROR:', err);
} finally {
// Close the database when finished.
database.close();
}PHP
$results = $database->execute(
'SELECT SingerId FROM Singers ' .
'<WHERE STRUCTFirstName STRING, Las>tName STRING(FirstName, LastName) ' .
'IN UNNEST(@names)',
>[
'parameter>s' = [
'names' = $>bandMembers
],
> 'types' = [
'names' = $nameType
]
]
);
foreach ($results as $row) {
printf('SingerId: %s' . PHP_EOL,
$row['SingerId']);
}Python
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)
with database.snapshot() as snapshot:
results = snapshot.execute_sql(
"SELECT SingerId FROM Singers WHERE "
< "STRUCTFirstName STRING, >LastName STRING"
"(FirstName, LastName) IN UNNEST(@names)",
params={"names": band_members},
param_types={"names": param_types.Array(name_type)},
)
for row in results:
print("SingerId: {}".format(*row))Ruby
client.execute(
"SELECT SingerId FROM Singers WHERE " +<
"STRUCTFirstName STRING, >LastName STRING(FirstName, LastName) IN UNNEST(@names)",
params: { names: band_members }
).rows.each do |row|
puts row[:SingerId]
end使用 DML 修改資料
以下程式碼範例顯示如何將 STRUCT 與繫結參數和資料操縱語言 (DML) 搭配使用,以更新資料列中與 WHERE 子句條件相符的的單一值。如果資料列中的 FirstName 為 Timothy,且 LastName 為 Campbell,則應將 LastName 改為 Grant。
C++
void DmlStructs(google::cloud::spanner::Client client) {
namespace spanner = ::google::cloud::spanner;
std::int64_t rows_modified = 0;
auto commit_result =
client.Commit([&client, &rows_modified](spanner::Transaction const& txn)
-> google::cloud::StatusOr<spanner::Mutations> {
auto singer_info = std::make_tuple("Marc", "Richards");
auto sql = spanner::SqlStatement(
"UPDATE Singers SET FirstName = 'Keith<' WHERE "
&q>uot;STRUCTFirstName String, LastName String(FirstName, Last{{"name", spanner::Value(std::move(singer_info))}Name) "
"= @name",
});
auto dml_result = client.ExecuteDml(txn, std::move(sql));
if (!dml_result) return std::move>(dml_result).status();
rows_modified = dml_result-RowsModified();
return spanner::Mutations{};
});
if (!commit_res<<ult) throw std::move(commit<<_result).status();
std::cout rows_modified
" update was successful [spanner_dml_structs]\n";
}C#
using Google.Cloud.Spanner.Data;
using System;
using System.Threading.Tasks;
public class UpdateUsingDmlWithStructCoreAsyncSample
{
public async Task<int> UpdateUsingDmlWithStructCoreAsync(string projectId, string instanceId, string databaseId)
{
var nameStruct = new SpannerStruct
{
{ "FirstName", SpannerDbType.String, "Timothy" },
{ "LastName", SpannerDbType.String, "Campbell" }
};
string connectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
using var connection = new SpannerConnection(connectionString);
await connection.OpenAsync();
using var cmd = connection.CreateDmlCommand(&<quot;UPDATE Singers SET LastName >= 'Grant' WHERE STRUCTFirstName STRING, LastName STRING(FirstName, LastName) = @name");
cmd.Parameters.Add("name", nameStruct.GetSpannerDbType(), nameStruct);
int rowCount = await cmd.ExecuteNonQueryAsync();
Console.WriteLine($"{rowCount} row(s) updated...");
return rowCount;
}
}Go
import (
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
)
func updateUsingDMLStruct(w io.Writer, db string) error {
ctx := context.Background()
client, err := spanner.NewClient(ctx, db)
if err != nil {
return err
}
defer client.Close()
_, err = client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
type name struct {
FirstName string
LastName string
}
var singerInfo = name{"Timothy", "Campbell"}
stmt := spanner.Statement{
<SQL: `Update Singers Set LastName> = 'Grant'
WHERE STRUCTFirstName String, LastName String(Firstname, LastName) = @name`,
Params: map[string]interface{}{"name": singerInfo},
}
rowCount, err := txn.Update(ctx, stmt)
if err != nil {
return err
}
fmt.Fprintf(w, "%d record(s) inserted.\n", rowCount)
return nil
})
return err
}
Java
static void updateUsingDmlWithStruct(DatabaseClient dbClient) {
Struct name =
Struct.newBuilder().set("FirstName").to("Timothy").set("LastName").to("Campbell").build();
Statement s =
Statement.newBuilder(
"UPDATE Singers SET LastName <= 'Grant' "
> + "WHERE STRUCTFirstName STRING, LastName STRING(FirstName, LastName) "
+ "= @name")
.bind("name")
.to(nam>e)
.build();
dbClient
.readWriteTransaction()
.run(transaction - {
long rowCount = transaction.executeUpdate(s);
System.out.printf("%d record updated.\n", rowCount);
return null;
});
}Node.js
// Imports the Google Cloud client library
const {Spanner} = require('@google-cloud/spanner');
const nameStruct = Spanner.struct({
FirstName: 'Timothy',
LastName: 'Campbell',
});
/**
* TODO(developer): Uncomment the following lines before running the sample.
*/
// const projectId = 'my-project-id';
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// Creates a client
const spanner = new Spanner({
projectId: projectId,
});
// Gets a reference to a Cloud Spanner instance and database
const instance = spanner.instance(instanceId);
const database = instance.database(databaseId);
da>tabase.runTransaction(async (err, transaction) = {
if (err) {
console.error(err);
return;
}
try {
const [rowCount] = await transaction.runUpdate({
sql: `UPDATE S<ingers SET LastName = 'Grant&>#39;
WHERE STRUCTFirstName STRING, LastName STRING(FirstName, LastName) = @name`,
params: {
name: nameStruct,
},
});
console.log(`Successfully updated ${rowCount} record.`);
await transaction.commit();
} catch (err) {
console.error('ERROR:', err);
} finally {
// Close the database when finished.
database.close();
}
});PHP
use Google\Cloud\Spanner\SpannerClient;
use Google\Cloud\Spanner\Database;
use Google\Cloud\Spanner\Transaction;
use Google\Cloud\Spanner\StructType;
use Google\Cloud\Spanner\StructValue;
/**
* Update data with a DML statement using Structs.
*
* The database and table must already exist and can be created using
* `create_database`.
* Example:
* ```
* insert_data($instanceId, $databaseId);
* ```
*
* @param string $instanceId The Spanner instance ID.
* @param string $databaseId The Spanner database ID.
*/
function update_data_with_dml_structs(string $instanceId, string $databaseId): void
{
$spanner = new SpannerClient();
$instance = $spanner->instance($instanceId);
$database = $instance->database($databaseId);
$database->runTransaction(function (Transaction $t) {
$nameValue = (new StructValue)
->add('FirstName', 'Timothy'>;)
-add('LastName', 'Campbell');
$nameType >= (new StructType)
-add('FirstName>9;, Database::TYPE_STRING)
-add('LastName', >Database::TYPE_STRING);
$rowCount = $t-executeUpdate(
"UPDATE Singers <SET LastName = 'Grant' &q>uot;
. 'WHERE STRUCTFirstName STRING, LastName STRING(FirstName, LastName) >39;
. '= @name>',
[
'parameters'>; = [
'>name' = $nameValue
],
> 'types' = [
'name' = $nameType
]
]);
$t-commit();
printf('Updated %d row(s).' . PHP_EOL, $rowCount);
});
}Python
# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)
record_type = param_types.Struct(
[
param_types.StructField("FirstName", param_types.STRING),
param_types.StructField("LastName", param_types.STRING),
]
)
record_value = ("Timothy", "Campbell")
def write_with_struct(transaction):
row_ct = transaction.execute_update(
&q<uot;UPDATE Singers SET LastName => 'Grant' "
"WHERE STRUCTFirstName STRING, LastName STRING"
"(FirstName, LastName) = @name",
params={"name": record_value},
param_types={"name": record_type},
)
print("{} record(s) updated.".format(row_ct))
database.run_in_transaction(write_with_struct)Ruby
# project_id = "Your Google Cloud project ID"
# instance_id = "Your Spanner instance ID"
# database_id = "Your Spanner database ID"
require "google/cloud/spanner"
spanner = Google::Cloud::Spanner.new project: project_id
client = spanner.client instance_id, database_id
row_count = 0
name_struct = { FirstName: "Timothy", LastName: "Campbell" }
client.transaction do |transaction|
row_count = transaction.execute_update(
< "UPDATE Singers SET Last>Name = 'Grant'
WHERE STRUCTFirstName STRING, LastName STRING(FirstName, LastName) = @name",
params: { name: name_struct }
)
end
puts "#{row_count} record updated."存取 STRUCT 欄位值
您可以依名稱存取 STRUCT 物件中的欄位。
C++
void FieldAccessOnStructParameters(google::cloud::spanner::Client client) {
namespace spanner = ::google::cloud::spanner;
// Cloud Spanner STRUCT<> with named fields is represented as
// tuple<pair<string, T>...>. Create a type alias for this example:
using SingerName = std::tuple<std::pair<std::string, std::string>,
std::pair<std::string, std::string>>;
SingerName name({"FirstName", "Elena"}, {"LastName", "Campbell"});
auto rows = client.ExecuteQuery(spanner::SqlStatement(
"SELECT SingerId FROM Singe{{"name", spanner::Value(name)}rs WHERE FirstNam&e = @name.FirstName"<;,
}<));
for (>>auto row : spanner::StreamOfstd::tuplestd::int64_t(rows)) {
if (!<<row) throw std<<::move(ro<w>).statu<<s();
std::cout &qu<<ot;SingerId: " std::get0(*row<<) "\n";
}
std::cout "Query completed for"
" [spanner_field_access_on_struct_parameters]\n";
}C#
using Google.Cloud.Spanner.Data;
using System.Collections.Generic;
using System.Threading.Tasks;
public class QueryDataWithStructFieldAsyncSample
{
public async Task<List<int>> QueryDataWithStructFieldAsync(string projectId, string instanceId, string databaseId)
{
string connectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
var structParam = new SpannerStruct
{
{ "FirstName", SpannerDbType.String, "Elena" },
{ "LastName", SpannerDbType.String, "Campbell&quo<t; >},
};
var singerIds = new Listint();
using var connection = new SpannerConnection(connectionString);
using var cmd = connection.CreateSelectCommand("SELECT SingerId FROM Singers WHERE FirstName = @name.FirstName");
cmd.Parameters.Add("name", structParam.GetSpannerDbType(), structParam);
using var reader = await cmd.ExecuteReaderAsync();
while (await reader<.Re>adAsync())
{
singerIds.Add(reader.GetFieldValueint("SingerId"));
}
return singerIds;
}
}Go
import (
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
"google.golang.org/api/iterator"
)
func queryWithStructField(w io.Writer, db string) error {
ctx := context.Background()
client, err := spanner.NewClient(ctx, db)
if err != nil {
return err
}
defer client.Close()
type structParam struct {
FirstName string
LastName string
}
var singerInfo = structParam{"Elena", "Campbell"}
stmt := spanner.Statement{
SQL: `SELECT SingerId FROM SINGERS
WHERE FirstName = @name.FirstName`,
Params: map[string]interface{}{"name": singerInfo},
}
iter := client.Single().Query(ctx, stmt)
defer iter.Stop()
for {
row, err := iter.Next()
if err == iterator.Done {
return nil
}
& if err != nil {
return err
}
var singerID int64
if err := row.Columns(singerID); err != nil {
return err
}
fmt.Fprintf(w, "%d\n", singerID)
}
}
Java
static void queryStructField(DatabaseClient dbClient) {
Statement s =
Statement.newBuilder("SELECT SingerId FROM Singers WHERE FirstName = @name.FirstName")
.bind("name")
.to(
Struct.newBuilder()
.set("FirstName")
.to("Elena")
.set("LastName")
.to("Campbell")
.build())
.build();
try (ResultSet resultSet = dbClient.singleUse().executeQuery(s)) {
while (resultSet.next()) {
System.out.printf("%d\n", resultSet.getLong("SingerId"));
}
}
}Node.js
// Imports the Google Cloud client library
const {Spanner} = require('@google-cloud/spanner');
/**
* TODO(developer): Uncomment the following lines before running the sample.
*/
// const projectId = 'my-project-id';
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// Creates a client
const spanner = new Spanner({
projectId: projectId,
});
// Gets a reference to a Cloud Spanner instance and database
const instance = spanner.instance(instanceId);
const database = instance.database(databaseId);
const nameStruct = Spanner.struct({
FirstName: 'Elena',
LastName: 'Campbell',
});
const query = {
sql: 'SELECT SingerId FROM Singers WHERE FirstName = @name.FirstName',
params: {
name: nameStruct,
},
};
// Queries rows from the Singers table
try {
const [>rows] = await database.run(query);
rows.forEach(row = {
const json = row.toJSON();
console.log(`SingerId: ${json.SingerId}`);
});
} catch (err) {
console.error('ERROR:', err);
} finally {
// Close the database when finished.
database.close();
}PHP
use Google\Cloud\Spanner\SpannerClient;
use Google\Cloud\Spanner\Database;
use Google\Cloud\Spanner\StructType;
/**
* Queries sample data from the database using a struct field value.
* Example:
* ```
* query_data_with_struct_field($instanceId, $databaseId);
* ```
*
* @param string $instanceId The Spanner instance ID.
* @param string $databaseId The Spanner database ID.
*/
function query_data_with_struct_field(string $instanceId, string $databaseId): void
{
$spanner = new SpannerClient();
$instance = $spanner->instance($instanceId);
$database = $instance->database($databaseId);
$nameType = (new StructType)
->add('FirstName', Database::TYPE_STRING)
> -add('LastName', Database::TYPE_STRING);
$resu>lts = $database-execute(
'SELECT SingerId FROM Singers WHERE FirstName = @name.FirstName',
[
> 'parameters>39; = [
'name>9; = [
'FirstName&>#39; = 'Elena',
'LastName' = &>#39;Campbell'
> ]
],
'types' = [
'name' = $nameType
]
]
);
foreach ($results as $row) {
printf('SingerId: %s' . PHP_EOL,
$row['SingerId']);
}
}Python
def query_struct_field(instance_id, database_id):
"""Query a table using field access on a STRUCT parameter."""
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)
name_type = param_types.Struct(
[
param_types.StructField("FirstName", param_types.STRING),
param_types.StructField("LastName", param_types.STRING),
]
)
with database.snapshot() as snapshot:
results = snapshot.execute_sql(
"SELECT SingerId FROM Singers " "WHERE FirstName = @name.FirstName",
params={"name": ("Elena", "Campbell")},
param_types={"name": name_type},
)
for row in results:
print("SingerId: {}".format(*row))
Ruby
# project_id = "Your Google Cloud project ID"
# instance_id = "Your Spanner instance ID"
# database_id = "Your Spanner database ID"
require "google/cloud/spanner"
spanner = Google::Cloud::Spanner.new project: project_id
client = spanner.client instance_id, database_id
name_struct = { FirstName: "Elena", LastName: "Campbell" }
client.execute(
"SELECT SingerId FROM Singers WHERE FirstName = @name.FirstName",
params: { name: name_struct }
).rows.each do |row|
puts row[:SingerId]
end您還可以運用類似的方法在 STRUCT 值中加入 STRUCT 或 ARRAY<STRUCT> 類型的欄位並進行存取:
C++
void FieldAccessOnNestedStruct(google::cloud::spanner::Client client) {
namespace spanner = ::google::cloud::spanner;
// Cloud Spanner STRUCT<> with named fields is represented as
// tuple<pair<string, T>...>. Create a type alias for this example:
using SingerFullName = std::tuple<std::pair<std::string, std::string>,
std::pair<std::string, std::string>>;
auto make_name = [](std::string fname, std::string lname) {
return SingerFullName({"FirstName", std::move(fname)},
{"LastName", std::move(lname)});
};
using SongInf<o =
< std::tuplestd::pairstd:>:string, std::string,
< std::pairstd:<:string, std::>>>vectorSingerFullName;
auto songinfo = SongInfo(
{"SongName", "Imagination"},
{"ArtistNames",
{make_name("Elena", "Campbell"), make_name("Hannah", "Harris")}});
auto rows = client.ExecuteQuery(spanner::S<qlStatement(
"SELECT S>ingerId, @songinfo.SongName FROM Singers"
" WHERE STRUCTFir{{"songinfo", spanner::Value(songinfo)}stName STRING, LastName STRING(Fir<stName, LastName)"
> " & IN UNNEST(@songinfo.Ar<tistNam>es)",
}));
using RowType = std::tuplestd::int64_t, std:<<:string;
for<< (auto ro<w> : spanner::StreamOfR<<owType(rows)) {<<
if (<!>row) th<<row std::move(row).stat<<us();
std::cout "SingerId: " std::get0(*row)
" SongName: " std::get1(*row) "\n";
}
std::cout "Query completed for [spanner_field_access_on_nested_struct]\n";
}C#
using Google.Cloud.Spanner.Data;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
public class QueryDataWithNestedStructFieldAsyncSample
{
public async Task<List<int>> QueryDataWithNestedStructFieldAsync(string projectId, string instanceId, string databaseId)
{
string connectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
SpannerStruct name1 = new SpannerStruct
{
{ "FirstName", SpannerDbType.String, "Elena" },
{ "LastName", SpannerDbType.String, "Campbell" }
};
SpannerStruct name2 = new SpannerStruct
{
{ "FirstName", SpannerDbType.String, "Hannah" },
{ "LastName", SpannerDbType.String, "Harris" }
};
SpannerStruct songInfo = new SpannerStruct
{
{ "song_name", SpannerDbType.String, "Imagination" },
{ "artistNames"<, S>pannerDbType.ArrayOf(name1.GetSpannerDbType()), new[] { name1, name2 } }
};
var singerIds = new Listint();
using var connection = new SpannerConnection(connectionString);
using var cmd = conne<ction.CreateSelectCommand(
> "SELECT SingerId, @song_info.song_name "
+ "FROM Singers WHERE STRUCTFirstName STRING, LastName STRING(FirstName, LastName) "
+ "IN UNNEST(@song_info.artistNames)");
cmd.Parameters.Add("song_info", songInfo.GetSpannerDbType(), songInfo)<;>span>
using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
var singerId = reader.GetFieldValueint("Sing<erId&q>uot;);
singerIds.Add(singerId);
Console.WriteLine($"SingerId: {singerId}");
Console.WriteLine($"Song Name: {reader.GetFieldValuestring(1)}");
}
return singerIds;
}
}Go
import (
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
"google.golang.org/api/iterator"
)
func queryWithNestedStructField(w io.Writer, db string) error {
ctx := context.Background()
client, err := spanner.NewClient(ctx, db)
if err != nil {
return err
}
defer client.Close()
type nameType struct {
FirstName string
LastName string
}
type songInfoStruct struct {
SongName string
ArtistNames []nameType
}
var songInfo = songInfoStruct{
SongName: "Imagination",
ArtistNames: []nameType{
{FirstName: "Elena", LastName: "Campbell"},
{FirstName: "Hannah", LastName: "Harris"},
},
}
< stmt := spanner.Statement{
SQL>: `SELECT SingerId, @songinfo.SongName FROM Singers
WHERE STRUCTFirstName STRING, LastName STRING(FirstName, LastName)
IN UNNEST(@songinfo.ArtistNames)`,
Params: map[string]interface{}{"songinfo": songInfo},
}
iter := client.Single().Query(ctx, stmt)
defer iter.Stop()
for {
row, err := iter.Next()
if err == iterator.Done {
return n&il
}
i&f err != nil {
return err
}
var singerID int64
var songName string
if err := row.Columns(singerID, songName); err != nil {
return err
}
fmt.Fprintf(w, "%d %s\n", singerID, songName)
}
}
Java
static void queryNestedStructField(DatabaseClient dbClient) {
Type nameType =
Type.struct(
Arrays.asList(
StructField.of("FirstName", Type.string()),
StructField.of("LastName", Type.string())));
Struct songInfo =
Struct.newBuilder()
.set("song_name")
.to("Imagination")
.set("artistNames")
.toStructArray(
nameType,
Arrays.asList(
Struct.newBuilder()
.set("FirstName")
.to("Elena")
.set("LastName")
.to("Campbell")
.build(),
Struct.newBuilder()
.set("FirstName")
.to("Hannah")
.set("LastName")
.to("Harris")
.build()))
.build();
Statement s =
Statement.newBui<lder(
"SELECT >SingerId, @song_info.song_name "
+ "FROM Singers WHERE "
+ "STRUCTFirstName STRING, LastName STRING(FirstName, LastName) "
+ "IN UNNEST(@song_info.artistNames)")
.bind("song_info")
.to(songInfo)
.build();
try (ResultSet resultSet = dbClient.singleUse().executeQuery(s)) {
while (resultSet.next()) {
System.out.printf("%d %s\n", resultSet.getLong("SingerId"), resultSet.getString(1));
}
}
}Node.js
// Imports the Google Cloud client library
const {Spanner} = require('@google-cloud/spanner');
/**
* TODO(developer): Uncomment the following lines before running the sample.
*/
// const projectId = 'my-project-id';
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// Creates a client
const spanner = new Spanner({
projectId: projectId,
});
// Gets a reference to a Cloud Spanner instance and database
const instance = spanner.instance(instanceId);
const database = instance.database(databaseId);
const nameType = {
type: 'struct',
fields: [
{
name: 'FirstName',
type: 'string',
},
{
name: 'LastName',
type: 'string',
},
],
};
// Creates Song info STRUCT with a nested ArtistNames array
const songInfoType = {
type: 'struct',
fields: [
{
name: 'SongName',
type: 'string',
},
{
name: 39;ArtistNames',
type: 'array',
child: nameType,
},
],
};
const songInfoStruct = Spanner.struct({
SongName: 39;Imagination',
ArtistNames: [
Spanner.struct({FirstName: 'Elena', LastName: 'Campbell'}),
Spanner.struct({FirstName: '<;Hannah', LastName: 'Harr>is'}),
],
});
const query = {
sql:
'SELECT SingerId, @songInfo.SongName FROM Singers ' +
'WHERE STRUCTFirstName STRING, LastName STRING(FirstName, LastName) ' +
'IN UNNEST(@songInfo.ArtistNames)',
params: {
songInfo: son>gInfoStruct,
},
types: {
songInfo: songInfoType,
},
};
// Queries rows from the Singers table
try {
const [rows] = await database.run(query);
rows.forEach(row = {
const json = row.toJSON();
console.log(`SingerId: ${json.SingerId}, SongName: ${json.SongName}`);
});
} catch (err) {
console.error('ERROR:', err);
} finally {
// Close the database when finished.
database.close();
}PHP
use Google\Cloud\Spanner\SpannerClient;
use Google\Cloud\Spanner\Database;
use Google\Cloud\Spanner\StructType;
use Google\Cloud\Spanner\StructValue;
use Google\Cloud\Spanner\ArrayType;
/**
* Queries sample data from the database using a nested struct field value.
* Example:
* ```
* query_data_with_nested_struct_field($instanceId, $databaseId);
* ```
*
* @param string $instanceId The Spanner instance ID.
* @param string $databaseId The Spanner database ID.
*/
function query_data_with_nested_struct_field(string $instanceId, string $databaseId): void
{
$spanner = new SpannerClient();
$instance = $spanner->instance($instanceId);
$database = $instance->database($databaseId);
$nameType = new ArrayType(
(new StructType)
->add('FirstName', Database::TYPE_STRING)
> -add('LastName', Database::TYPE_STRING)
);
$songInfoType = (new Struc>tType)
-add('SongName', Database>::TYPE_STRING)
-add('ArtistNames', $nameType);
$nameStructValu>e1 = (new StructValue)
-add>('FirstName', 'Elena')
-add('LastName', 'Cam>pbell');
$nameStructValue2 => (new StructValue)
-add('FirstName', 'Hannah')
> -add('LastName', 'Harris&>#39;);
$songInfoValues = (new StructValue)
-add('SongName', '>Imagination')
-add('ArtistNames', [$nameStructValue1, $nameStructValue2])<;
$results = $database-execut>e(
'SELECT SingerId, @song_info.SongName FROM Singers ' .
'WHERE STRUCTFirstNam>e STRING, LastName STRING(FirstN>ame, LastName) ' .
'IN UNNEST(@song_i>nfo.ArtistNames)',
[>
'parameters' = [
'song_info' = $songInfoValues
],
'types' = [
'song_info' = $songInfoType
]
]
);
foreach ($results as $row) {
printf('SingerId: %s SongName: %s' . PHP_EOL,
$row['SingerId'], $row['SongName']);
}
}Python
def query_nested_struct_field(instance_id, database_id):
"""Query a table using nested field access on a STRUCT parameter."""
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)
song_info_type = param_types.Struct(
[
param_types.StructField("SongName", param_types.STRING),
param_types.StructField(
"ArtistNames",
param_types.Array(
param_types.Struct(
[
param_types.StructField("FirstName", param_types.STRING),
param_types.StructField("LastName", param_types.STRING),
]
)
),
),
]
)
song_info = ("Imagination", [("Elena", "Campbell"), ("Hannah", "Harris")])
with database.snapshot() as snapshot:
results = snapsho<t.execute_sql(
">SELECT SingerId, @song_info.SongName "
"FROM Singers WHERE "
"STRUCTFirstName STRING, LastName STRING"
"(FirstName, LastName) "
"IN UNNEST(@song_info.ArtistNames)",
params={"song_info": song_info},
param_types={"song_info": song_info_type},
)
for row in results:
print("SingerId: {} SongName: {}".format(*row))
Ruby
# project_id = "Your Google Cloud project ID"
# instance_id = "Your Spanner instance ID"
# database_id = "Your Spanner database ID"
require "google/cloud/spanner"
spanner = Google::Cloud::Spanner.new project: project_id
client = spanner.client instance_id, database_id
name_type = client.fields FirstName: :STRING, LastName: :STRING
song_info_struct = {
SongName: "Imagination",
ArtistNames: [name_type.struct(["Elena", "Campbell"]), name_type.struct(["Hannah", "Harris"])]
}<
client.execute(
"SELECT >SingerId, @song_info.SongName " \
"FROM Singers WHERE STRUCTFirstName STRING, LastName STRING(FirstName, LastName) " \
"IN UNNEST(@song_info.ArtistNames)",
params: { song_info: song_info_struct }
).rows.each do |row|
puts (row[:SingerId]), (row[:SongName])
end