Insert, update, and delete data using data manipulation language (DML)
Stay organized with collections
Save and categorize content based on your preferences.
This page describes how to insert, update, and delete Spanner
data using Data Manipulation Language (DML) statements. You can run DML
statements using the client libraries, the
Google Cloud console, and the gcloud
command-line tool. You can run Partitioned DML
statements using the client libraries and the gcloud
command-line tool.
For the complete DML syntax reference, see Data Manipulation Language syntax for GoogleSQL-dialect databases or PostgreSQL data manipulation language for PostgreSQL-dialect databases
Use DML
DML supports INSERT, UPDATE, and DELETE statements in the
Google Cloud console, Google Cloud CLI, and client libraries.
Locking
You execute DML statements inside read-write transactions. When Spanner reads data, it
acquires shared read locks on limited portions of the row ranges that you read. Specifically, it
acquires these locks only on the columns you access. The locks can include data that does not
satisfy the filter condition of the WHERE clause.
When Spanner modifies data using DML statements, it acquires exclusive locks on the specific data that you are modifying. In addition, it acquires shared locks in the same way as when you read data. If your request includes large row ranges, or an entire table, the shared locks might prevent other transactions from making progress in parallel.
To modify data as efficiently as possible, use a WHERE clause that enables
Spanner to read only the necessary rows. You can achieve this goal with a filter on the
primary key, or on the key of a secondary index. The WHERE clause limits the scope of
the shared locks and enables Spanner to process the update more efficiently.
For example, suppose that one of the musicians in the Singers table changes their
first name, and you need to update the name in your database. You could execute the following DML
statement, but it forces Spanner to scan the entire table and acquires shared locks that
cover the entire table. As a result, Spanner must read more data than necessary, and
concurrent transactions cannot modify the data in parallel:
-- ANTI-PATTERN: SENDING AN UPDATE WITHOUT THE PRIMARY KEY COLUMN
-- IN THE WHERE CLAUSE
UPDATESingersSETFirstName="Marcel"
WHEREFirstName="Marc"ANDLastName="Richards";
To make the update more efficient, include the SingerId column in the
WHERE clause. The SingerId column is the only primary key column for
the Singers table:
-- ANTI-PATTERN: SENDING AN UPDATE THAT MUST SCAN THE ENTIRE TABLE
UPDATESingersSETFirstName="Marcel"
WHEREFirstName="Marc"ANDLastName="Richards"
If there is no index on FirstName or LastName, you need to
scan the entire table to find the target singers. If you don't want to add a secondary
index to make the update more efficient, then include the SingerId column
in the WHERE clause.
The SingerId column is the only primary key column for the
Singers table. To find it, run SELECT in a separate,
read-only transaction prior to the update transaction:
SELECTSingerId
FROMSingers
WHEREFirstName="Marc"ANDLastName="Richards"
--Recommended:Includingaseekablefilterinthewhereclause
UPDATESingersSETFirstName="Marcel"
WHERESingerId=1;
Concurrency
Spanner sequentially executes all the SQL statements (SELECT,
INSERT, UPDATE, and DELETE) within a transaction. They are not executed
concurrently. The only exception is that Spanner might execute
multiple SELECT statements concurrently, because they are read-only operations.
Transaction limits
A transaction that includes DML statements has the same limits as any other transaction. If you have large-scale changes, consider using Partitioned DML.
If the DML statements in a transaction result in more than 80,000 mutations, the DML statement that pushes the transaction over the limit returns a
BadUsageerror with a message about too many mutations.If the DML statements in a transaction result in a transaction that is larger than 100 MiB, the DML statement that pushes the transaction over the limit returns a
BadUsageerror with a message about the transaction exceeding the size limit.
Mutations performed using DML are not returned to the client. They are merged into the commit request when it is committed, and they count towards the maximum size limits. Even if the size of the commit request that you send is small, the transaction might still exceed the allowed size limit.
Run statements in the Google Cloud console
Use the following steps to execute a DML statement in the Google Cloud console.
Go to the Spanner Instances page.
Select your project in the drop-down list in the toolbar.
Click the name of the instance that contains your database to go to the Instance details page.
In the Overview tab, click the name of your database. The Database details page appears.
Click Spanner Studio.
Enter a DML statement. For example, the following statement adds a new row to the
Singerstable.INSERT Singers (SingerId, FirstName, LastName) VALUES (1, 'Marc', 'Richards')Click Run query. The Google Cloud console displays the result.
Execute statements with the Google Cloud CLI
To execute DML statements, use the gcloud spanner databases execute-sql
command. The following example adds a new row to the Singers table.
gcloudspannerdatabasesexecute-sqlexample-db--instance=test-instance\
--sql="INSERT Singers (SingerId, FirstName, LastName) VALUES (1, 'Marc', 'Richards')"
Modify data using the client library
To execute DML statements using the client library:
- Create a read-write transaction.
- Call the client library method for DML execution and pass in the DML statement.
- Use the return value of the DML execution method to get the number of rows inserted, updated, or deleted.
The following code example inserts a new row into the Singers table.
C++
You use the ExecuteDml() function to execute a DML statement.
voidDmlStandardInsert(google::cloud::spanner::Clientclient){
using::google::cloud::StatusOr;
namespacespanner=::google::cloud::spanner;
std::int64_trows_inserted;
autocommit_result=client.Commit(
[&client,&rows_inserted](
spanner::Transactiontxn)->StatusOr<spanner::Mutations>{
autoinsert=client.ExecuteDml(
std::move(txn),
spanner::SqlStatement(
"INSERT INTO Singers (SingerId, FirstName, LastName)"
" VALUES (10, 'Virginia', 'Watson')"));
if(!insert)returnstd::move(insert).status();
rows_inserted=insert->RowsModified();
returnspanner::Mutations{};
});
if(!commit_result)throwstd::move(commit_result).status();
std::cout << "Rows inserted: " << rows_inserted;
std::cout << "Insert was successful [spanner_dml_standard_insert]\n";
}C#
You use the ExecuteNonQueryAsync() method to execute a DML statement.
usingGoogle.Cloud.Spanner.Data ;
usingSystem;
usingSystem.Threading.Tasks;
publicclassInsertUsingDmlCoreAsyncSample
{
publicasyncTask<int>InsertUsingDmlCoreAsync(stringprojectId,stringinstanceId,stringdatabaseId)
{
stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
usingvarconnection=newSpannerConnection (connectionString);
awaitconnection.OpenAsync ();
usingvarcmd=connection.CreateDmlCommand ("INSERT Singers (SingerId, FirstName, LastName) VALUES (10, 'Virginia', 'Watson')");
introwCount=awaitcmd.ExecuteNonQueryAsync();
Console.WriteLine($"{rowCount} row(s) inserted...");
returnrowCount;
}
}Go
You use the Update() method to execute a DML statement.
import(
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
)
funcinsertUsingDML(wio.Writer,dbstring)error{
ctx:=context.Background()
client,err:=spanner.NewClient(ctx,db)
iferr!=nil{
returnerr
}
deferclient.Close()
_,err=client.ReadWriteTransaction(ctx,func(ctxcontext.Context,txn*spanner.ReadWriteTransaction)error{
stmt:=spanner.Statement {
SQL:`INSERT Singers (SingerId, FirstName, LastName)
VALUES (10, 'Virginia', 'Watson')`,
}
rowCount,err:=txn.Update(ctx,stmt)
iferr!=nil{
returnerr
}
fmt.Fprintf(w,"%d record(s) inserted.\n",rowCount)
returnnil
})
returnerr
}
Java
You use the executeUpdate() method to execute a DML statement.
staticvoidinsertUsingDml(DatabaseClientdbClient){
dbClient
.readWriteTransaction()
.run(transaction->{
Stringsql=
"INSERT INTO Singers (SingerId, FirstName, LastName) "
+" VALUES (10, 'Virginia', 'Watson')";
longrowCount=transaction.executeUpdate(Statement.of(sql));
System.out.printf("%d record inserted.\n",rowCount);
returnnull;
});
}Node.js
You use the runUpdate() method to execute a DML statement.
// 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
constspanner=newSpanner ({
projectId:projectId,
});
// Gets a reference to a Cloud Spanner instance and database
constinstance=spanner.instance(instanceId);
constdatabase=instance.database(databaseId);
database.runTransaction (async(err,transaction)=>{
if(err){
console.error(err);
return;
}
try{
const[rowCount]=awaittransaction.runUpdate ({
sql:'INSERT Singers (SingerId, FirstName, LastName) VALUES (10, @firstName, @lastName)',
params:{
firstName:'Virginia',
lastName:'Watson',
},
});
console.log(
`Successfully inserted ${rowCount} record into the Singers table.`,
);
awaittransaction.commit();
}catch(err){
console.error('ERROR:',err);
}finally{
// Close the database when finished.
database.close();
}
});PHP
You use the executeUpdate() method to execute a DML statement.
use Google\Cloud\Spanner\SpannerClient;
use Google\Cloud\Spanner\Transaction;
/**
* Inserts sample data into the given database with a DML statement.
*
* 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 insert_data_with_dml(string $instanceId, string $databaseId): void
{
$spanner = new SpannerClient();
$instance = $spanner->instance($instanceId);
$database = $instance->database($databaseId);
$database->runTransaction(function (Transaction $t) {
$rowCount = $t->executeUpdate(
'INSERT Singers (SingerId, FirstName, LastName) '
. " VALUES (10, 'Virginia', 'Watson')");
$t->commit();
printf('Inserted %d row(s).' . PHP_EOL, $rowCount);
});
}Python
You use the execute_update() method to execute a DML statement.
# 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)
definsert_singers(transaction):
row_ct = transaction.execute_update(
"INSERT INTO Singers (SingerId, FirstName, LastName) "
" VALUES (10, 'Virginia', 'Watson')"
)
print("{} record(s) inserted.".format(row_ct))
database.run_in_transaction(insert_singers)Ruby
You use the execute_update() method to execute a DML statement.
# 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.newproject:project_id
client=spanner.clientinstance_id,database_id
row_count=0
client.transactiondo|transaction|
row_count=transaction.execute_update(
"INSERT INTO Singers (SingerId, FirstName, LastName) VALUES (10, 'Virginia', 'Watson')"
)
end
puts"#{row_count} record inserted."The following code example updates the MarketingBudget column of the Albums
table based on a WHERE clause.
C++
voidDmlStandardUpdate(google::cloud::spanner::Clientclient){
using::google::cloud::StatusOr;
namespacespanner=::google::cloud::spanner;
autocommit_result=client.Commit(
[&client](spanner::Transactiontxn)->StatusOr<spanner::Mutations>{
autoupdate=client.ExecuteDml(
std::move(txn),
spanner::SqlStatement(
"UPDATE Albums SET MarketingBudget = MarketingBudget * 2"
" WHERE SingerId = 1 AND AlbumId = 1"));
if(!update)returnstd::move(update).status();
returnspanner::Mutations{};
});
if(!commit_result)throwstd::move(commit_result).status();
std::cout << "Update was successful [spanner_dml_standard_update]\n";
}C#
usingGoogle.Cloud.Spanner.Data ;
usingSystem;
usingSystem.Threading.Tasks;
publicclassUpdateUsingDmlCoreAsyncSample
{
publicasyncTask<int>UpdateUsingDmlCoreAsync(stringprojectId,stringinstanceId,stringdatabaseId)
{
stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
usingvarconnection=newSpannerConnection (connectionString);
awaitconnection.OpenAsync ();
usingvarcmd=connection.CreateDmlCommand ("UPDATE Albums SET MarketingBudget = MarketingBudget * 2 WHERE SingerId = 1 and AlbumId = 1");
introwCount=awaitcmd.ExecuteNonQueryAsync();
Console.WriteLine($"{rowCount} row(s) updated...");
returnrowCount;
}
}Go
import(
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
)
funcupdateUsingDML(wio.Writer,dbstring)error{
ctx:=context.Background()
client,err:=spanner.NewClient(ctx,db)
iferr!=nil{
returnerr
}
deferclient.Close()
_,err=client.ReadWriteTransaction(ctx,func(ctxcontext.Context,txn*spanner.ReadWriteTransaction)error{
stmt:=spanner.Statement {
SQL:`UPDATE Albums
SET MarketingBudget = MarketingBudget * 2
WHERE SingerId = 1 and AlbumId = 1`,
}
rowCount,err:=txn.Update(ctx,stmt)
iferr!=nil{
returnerr
}
fmt.Fprintf(w,"%d record(s) updated.\n",rowCount)
returnnil
})
returnerr
}
Java
staticvoidupdateUsingDml(DatabaseClientdbClient){
dbClient
.readWriteTransaction()
.run(transaction->{
Stringsql=
"UPDATE Albums "
+"SET MarketingBudget = MarketingBudget * 2 "
+"WHERE SingerId = 1 and AlbumId = 1";
longrowCount=transaction.executeUpdate(Statement.of(sql));
System.out.printf("%d record updated.\n",rowCount);
returnnull;
});
}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
constspanner=newSpanner ({
projectId:projectId,
});
// Gets a reference to a Cloud Spanner instance and database
constinstance=spanner.instance(instanceId);
constdatabase=instance.database(databaseId);
database.runTransaction (async(err,transaction)=>{
if(err){
console.error(err);
return;
}
try{
const[rowCount]=awaittransaction.runUpdate ({
sql:`UPDATE Albums SET MarketingBudget = MarketingBudget * 2
WHERE SingerId = 1 and AlbumId = 1`,
});
console.log(`Successfully updated ${rowCount} record.`);
awaittransaction.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\Transaction;
/**
* Updates sample data in the database with a DML statement.
*
* This requires the `MarketingBudget` column which must be created before
* running this sample. You can add the column by running the `add_column`
* sample or by running this DDL statement against your database:
*
* ALTER TABLE Albums ADD COLUMN MarketingBudget INT64
*
* Example:
* ```
* update_data($instanceId, $databaseId);
* ```
*
* @param string $instanceId The Spanner instance ID.
* @param string $databaseId The Spanner database ID.
*/
function update_data_with_dml(string $instanceId, string $databaseId): void
{
$spanner = new SpannerClient();
$instance = $spanner->instance($instanceId);
$database = $instance->database($databaseId);
$database->runTransaction(function (Transaction $t) {
$rowCount = $t->executeUpdate(
'UPDATE Albums '
. 'SET MarketingBudget = MarketingBudget * 2 '
. 'WHERE SingerId = 1 and AlbumId = 1');
$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)
defupdate_albums(transaction):
row_ct = transaction.execute_update(
"UPDATE Albums "
"SET MarketingBudget = MarketingBudget * 2 "
"WHERE SingerId = 1 and AlbumId = 1"
)
print("{} record(s) updated.".format(row_ct))
database.run_in_transaction(update_albums)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.newproject:project_id
client=spanner.clientinstance_id,database_id
row_count=0
client.transactiondo|transaction|
row_count=transaction.execute_update(
"UPDATE Albums
SET MarketingBudget = MarketingBudget * 2
WHERE SingerId = 1 and AlbumId = 1"
)
end
puts"#{row_count} record updated."The following code example deletes all the rows in the Singers table where
the FirstName column is Alice.
C++
voidDmlStandardDelete(google::cloud::spanner::Clientclient){
using::google::cloud::StatusOr;
namespacespanner=::google::cloud::spanner;
autocommit_result=client.Commit([&client](spanner::Transactiontxn)
->StatusOr<spanner::Mutations>{
autodele=client.ExecuteDml(
std::move(txn),
spanner::SqlStatement("DELETE FROM Singers WHERE FirstName = 'Alice'"));
if(!dele)returnstd::move(dele).status();
returnspanner::Mutations{};
});
if(!commit_result)throwstd::move(commit_result).status();
std::cout << "Delete was successful [spanner_dml_standard_delete]\n";
}C#
usingGoogle.Cloud.Spanner.Data ;
usingSystem;
usingSystem.Threading.Tasks;
publicclassDeleteUsingDmlCoreAsyncSample
{
publicasyncTask<int>DeleteUsingDmlCoreAsync(stringprojectId,stringinstanceId,stringdatabaseId)
{
stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
usingvarconnection=newSpannerConnection (connectionString);
awaitconnection.OpenAsync ();
usingvarcmd=connection.CreateDmlCommand ("DELETE FROM Singers WHERE FirstName = 'Alice'");
introwCount=awaitcmd.ExecuteNonQueryAsync();
Console.WriteLine($"{rowCount} row(s) deleted...");
returnrowCount;
}
}Go
import(
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
)
funcdeleteUsingDML(wio.Writer,dbstring)error{
ctx:=context.Background()
client,err:=spanner.NewClient(ctx,db)
iferr!=nil{
returnerr
}
deferclient.Close()
_,err=client.ReadWriteTransaction(ctx,func(ctxcontext.Context,txn*spanner.ReadWriteTransaction)error{
stmt:=spanner.Statement {SQL:`DELETE FROM Singers WHERE FirstName = 'Alice'`}
rowCount,err:=txn.Update(ctx,stmt)
iferr!=nil{
returnerr
}
fmt.Fprintf(w,"%d record(s) deleted.\n",rowCount)
returnnil
})
returnerr
}
Java
staticvoiddeleteUsingDml(DatabaseClientdbClient){
dbClient
.readWriteTransaction()
.run(transaction->{
Stringsql="DELETE FROM Singers WHERE FirstName = 'Alice'";
longrowCount=transaction.executeUpdate(Statement.of(sql));
System.out.printf("%d record deleted.\n",rowCount);
returnnull;
});
}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
constspanner=newSpanner ({
projectId:projectId,
});
// Gets a reference to a Cloud Spanner instance and database
constinstance=spanner.instance(instanceId);
constdatabase=instance.database(databaseId);
database.runTransaction (async(err,transaction)=>{
if(err){
console.error(err);
return;
}
try{
const[rowCount]=awaittransaction.runUpdate ({
sql:"DELETE FROM Singers WHERE FirstName = 'Alice'",
});
console.log(`Successfully deleted ${rowCount} record.`);
awaittransaction.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\Transaction;
/**
* Deletes sample data in the database with a DML statement.
*
* @param string $instanceId The Spanner instance ID.
* @param string $databaseId The Spanner database ID.
*/
function delete_data_with_dml(string $instanceId, string $databaseId): void
{
$spanner = new SpannerClient();
$instance = $spanner->instance($instanceId);
$database = $instance->database($databaseId);
$database->runTransaction(function (Transaction $t) {
$rowCount = $t->executeUpdate(
"DELETE FROM Singers WHERE FirstName = 'Alice'");
$t->commit();
printf('Deleted %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)
defdelete_singers(transaction):
row_ct = transaction.execute_update(
"DELETE FROM Singers WHERE FirstName = 'Alice'"
)
print("{} record(s) deleted.".format(row_ct))
database.run_in_transaction(delete_singers)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.newproject:project_id
client=spanner.clientinstance_id,database_id
row_count=0
client.transactiondo|transaction|
row_count=transaction.execute_update(
"DELETE FROM Singers WHERE FirstName = 'Alice'"
)
end
puts"#{row_count} record deleted."The following example, for GoogleSQL-dialect databases only, uses a
STRUCT with bound parameters
to update the LastName in rows filtered by FirstName and LastName.
GoogleSQL
C++
voidDmlStructs(google::cloud::spanner::Clientclient){
namespacespanner=::google::cloud::spanner;
std::int64_trows_modified=0;
autocommit_result=
client.Commit([&client,&rows_modified](spanner::Transactionconst&txn)
->google::cloud::StatusOr<spanner::Mutations>{
autosinger_info=std::make_tuple("Marc","Richards");
autosql=spanner::SqlStatement(
"UPDATE Singers SET FirstName = 'Keith' WHERE "
"STRUCT<FirstName String, LastName String>(FirstName, LastName) "
"= @name",
{{"name", spanner::Value(std::move(singer_info))}});
autodml_result=client.ExecuteDml(txn,std::move(sql));
if(!dml_result)returnstd::move(dml_result).status();
rows_modified=dml_result->RowsModified();
returnspanner::Mutations{};
});
if(!commit_result)throwstd::move(commit_result).status();
std::cout << rows_modified
<< " update was successful [spanner_dml_structs]\n";
}C#
usingGoogle.Cloud.Spanner.Data ;
usingSystem;
usingSystem.Threading.Tasks;
publicclassUpdateUsingDmlWithStructCoreAsyncSample
{
publicasyncTask<int>UpdateUsingDmlWithStructCoreAsync(stringprojectId,stringinstanceId,stringdatabaseId)
{
varnameStruct=newSpannerStruct
{
{"FirstName",SpannerDbType .String ,"Timothy"},
{"LastName",SpannerDbType .String ,"Campbell"}
};
stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
usingvarconnection=newSpannerConnection (connectionString);
awaitconnection.OpenAsync ();
usingvarcmd=connection.CreateDmlCommand ("UPDATE Singers SET LastName = 'Grant' WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) = @name");
cmd.Parameters .Add("name",nameStruct.GetSpannerDbType (),nameStruct);
introwCount=awaitcmd.ExecuteNonQueryAsync();
Console.WriteLine($"{rowCount} row(s) updated...");
returnrowCount;
}
}Go
import(
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
)
funcupdateUsingDMLStruct(wio.Writer,dbstring)error{
ctx:=context.Background()
client,err:=spanner.NewClient(ctx,db)
iferr!=nil{
returnerr
}
deferclient.Close()
_,err=client.ReadWriteTransaction(ctx,func(ctxcontext.Context,txn*spanner.ReadWriteTransaction)error{
typenamestruct{
FirstNamestring
LastNamestring
}
varsingerInfo=name{"Timothy","Campbell"}
stmt:=spanner.Statement {
SQL:`Update Singers Set LastName = 'Grant'
WHERE STRUCT<FirstName String, LastName String>(Firstname, LastName) = @name`,
Params:map[string]interface{}{"name":singerInfo},
}
rowCount,err:=txn.Update(ctx,stmt)
iferr!=nil{
returnerr
}
fmt.Fprintf(w,"%d record(s) inserted.\n",rowCount)
returnnil
})
returnerr
}
Java
staticvoidupdateUsingDmlWithStruct(DatabaseClientdbClient){
Structname=
Struct.newBuilder().set("FirstName").to("Timothy").set("LastName").to("Campbell").build();
Statements=
Statement.newBuilder(
"UPDATE Singers SET LastName = 'Grant' "
+"WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) "
+"= @name")
.bind("name")
.to(name)
.build();
dbClient
.readWriteTransaction()
.run(transaction->{
longrowCount=transaction.executeUpdate(s);
System.out.printf("%d record updated.\n",rowCount);
returnnull;
});
}Node.js
// Imports the Google Cloud client library
const{Spanner}=require('@google-cloud/spanner');
constnameStruct=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
constspanner=newSpanner ({
projectId:projectId,
});
// Gets a reference to a Cloud Spanner instance and database
constinstance=spanner.instance(instanceId);
constdatabase=instance.database(databaseId);
database.runTransaction (async(err,transaction)=>{
if(err){
console.error(err);
return;
}
try{
const[rowCount]=awaittransaction.runUpdate ({
sql:`UPDATE Singers SET LastName = 'Grant'
WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) = @name`,
params:{
name:nameStruct,
},
});
console.log(`Successfully updated ${rowCount} record.`);
awaittransaction.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', Database::TYPE_STRING)
->add('LastName', Database::TYPE_STRING);
$rowCount = $t->executeUpdate(
"UPDATE Singers SET LastName = 'Grant' "
. 'WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) '
. '= @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")
defwrite_with_struct(transaction):
row_ct = transaction.execute_update(
"UPDATE Singers SET LastName = 'Grant' "
"WHERE STRUCT<FirstName 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.newproject:project_id
client=spanner.clientinstance_id,database_id
row_count=0
name_struct={FirstName:"Timothy",LastName:"Campbell"}
client.transactiondo|transaction|
row_count=transaction.execute_update(
"UPDATE Singers SET LastName = 'Grant'
WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) = @name",
params:{name:name_struct}
)
end
puts"#{row_count} record updated."Modify data with the returning DML statements
The THEN RETURN clause (GoogleSQL-dialect databases)
or RETURNING clause (PostgreSQL-dialect databases)
is intended for scenarios where you want to fetch data from modified rows. This
is especially useful when you want to view unspecified values in the DML
statements, default values, or generated columns.
To execute returning DML statements using the client library:
- Create a read-write transaction.
- Call the client library method for query execution and pass in the returning DML statement to obtain results.
The following code example inserts a new row into the Singers table, and it
returns the generated column FullName of the inserted records.
GoogleSQL
C++
voidInsertUsingDmlReturning(google::cloud::spanner::Clientclient){
//InsertrecordsintoSINGERStableandreturnthegeneratedcolumn
//FullNameoftheinsertedrecordsusing`THEN RETURN FullName`.
autocommit=client.Commit(
[&client](google::cloud::spanner::Transactiontxn)
->google::cloud::StatusOr<google::cloud::spanner::Mutations>{
autosql=google::cloud::spanner::SqlStatement(R"""(
INSERT INTO Singers (SingerId, FirstName, LastName)
VALUES (12, 'Melissa', 'Garcia'),
(13, 'Russell', 'Morales'),
(14, 'Jacqueline', 'Long'),
(15, 'Dylan', 'Shaw')
THEN RETURN FullName
)""");
usingRowType=std::tuple<std::string>;
autorows=client.ExecuteQuery(std::move(txn),std::move(sql));
//Note:Thismutatormightbere-run,oritseffectsdiscarded,so
//changingnon-transactionalstate(e.g.,byproducingoutput)is,
//ingeneral,notsomethingtobeimitated.
for(auto&row:google::cloud::spanner::StreamOf<RowType>(rows)){
if(!row)returnstd::move(row).status();
std::cout << "FullName: " << std::get<0>(*row) << "\n";
}
std::cout << "Inserted row(s) count: " << rows.RowsModified() << "\n";
returngoogle::cloud::spanner::Mutations{};
});
if(!commit)throwstd::move(commit).status();
}C#
usingGoogle.Cloud.Spanner.Data ;
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Threading.Tasks;
publicclassInsertUsingDmlReturningAsyncSample
{
publicasyncTask<List<string>>InsertUsingDmlReturningAsync(stringprojectId,stringinstanceId,stringdatabaseId)
{
stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
usingvarconnection=newSpannerConnection (connectionString);
awaitconnection.OpenAsync ();
// Insert records into the SINGERS table and return the
// generated column FullName of the inserted records using
// 'THEN RETURN FullName'.
// It is also possible to return all columns of all the
// inserted records by using 'THEN RETURN *'.
usingvarcmd=connection.CreateDmlCommand (
@"INSERT INTO Singers(SingerId, FirstName, LastName) VALUES
(6, 'Melissa', 'Garcia'),
(7, 'Russell', 'Morales'),
(8, 'Jacqueline', 'Long'),
(9, 'Dylan', 'Shaw') THEN RETURN FullName");
varreader=awaitcmd.ExecuteReaderAsync ();
varinsertedSingerNames=newList<string>();
while(awaitreader.ReadAsync ())
{
insertedSingerNames.Add(reader.GetFieldValue<string>("FullName"));
}
Console.WriteLine($"{insertedSingerNames.Count} row(s) inserted...");
returninsertedSingerNames;
}
}Go
import(
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
"google.golang.org/api/iterator"
)
funcinsertUsingDMLReturning(wio.Writer,dbstring)error{
ctx:=context.Background()
client,err:=spanner.NewClient(ctx,db)
iferr!=nil{
returnerr
}
deferclient.Close()
// Insert records into the SINGERS table and returns the
// generated column FullName of the inserted records using
// 'THEN RETURN FullName'.
// It is also possible to return all columns of all the
// inserted records by using 'THEN RETURN *'.
_,err=client.ReadWriteTransaction(ctx,func(ctxcontext.Context,txn*spanner.ReadWriteTransaction)error{
stmt:=spanner.Statement {
SQL:`INSERT INTO Singers (SingerId, FirstName, LastName)
VALUES (21, 'Melissa', 'Garcia'),
(22, 'Russell', 'Morales'),
(23, 'Jacqueline', 'Long'),
(24, 'Dylan', 'Shaw')
THEN RETURN FullName`,
}
iter:=txn.Query(ctx,stmt)
deferiter.Stop()
for{
row,err:=iter.Next()
iferr==iterator.Done{
break
}
iferr!=nil{
returnerr
}
varfullNamestring
iferr:=row.Columns (&fullName);err!=nil{
returnerr
}
fmt.Fprintf(w,"%s\n",fullName)
}
fmt.Fprintf(w,"%d record(s) inserted.\n",iter.RowCount)
returnnil
})
returnerr
}
Java
importcom.google.cloud.spanner.DatabaseClient ;
importcom.google.cloud.spanner.DatabaseId ;
importcom.google.cloud.spanner.ResultSet ;
importcom.google.cloud.spanner.Spanner ;
importcom.google.cloud.spanner.SpannerOptions ;
importcom.google.cloud.spanner.Statement ;
publicclass InsertUsingDmlReturningSample{
staticvoidinsertUsingDmlReturning(){
// TODO(developer): Replace these variables before running the sample.
finalStringprojectId="my-project";
finalStringinstanceId="my-instance";
finalStringdatabaseId="my-database";
insertUsingDmlReturning(projectId,instanceId,databaseId);
}
staticvoidinsertUsingDmlReturning(StringprojectId,StringinstanceId,StringdatabaseId){
try(Spanner spanner=
SpannerOptions .newBuilder()
.setProjectId(projectId)
.build()
.getService()){
finalDatabaseClient dbClient=
spanner.getDatabaseClient(DatabaseId .of(projectId,instanceId,databaseId));
// Insert records into the SINGERS table and returns the
// generated column FullName of the inserted records using
// ‘THEN RETURN FullName’.
// It is also possible to return all columns of all the
// inserted records by using ‘THEN RETURN *’.
dbClient
.readWritreadWriteTransaction .run(
transaction->{
Stringsql=
"INSERT INTO Singers (SingerId, FirstName, LastName) VALUES "
+"(12, 'Melissa', 'Garcia'), "
+"(13, 'Russell', 'Morales'), "
+"(14, 'Jacqueline', 'Long'), "
+"(15, 'Dylan', 'Shaw') THEN RETURN FullName";
// readWriteTransaction.executeQuery(..) API should be used for executing
// DML statements with RETURNING clause.
try(ResultSeResultSetet=transaction.executeQuery(StatemenStatement )){
while(resultSet.next()){
System.out.println(resultSet.getString(0));
}
System.out.printf(
"Inserted row(s) count: %d\n",resultSet.getStats().getRowCountExact());
}
returnnull;
});
}
}
}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
constspanner=newSpanner ({
projectId:projectId,
});
functioninsertUsingDmlReturning(instanceId,databaseId){
// Gets a reference to a Cloud Spanner instance and database.
constinstance=spanner.instance(instanceId);
constdatabase=instance.database(databaseId);
database.runTransaction (async(err,transaction)=>{
if(err){
console.error(err);
return;
}
try{
const[rows,stats]=awaittransaction.run({
sql:'INSERT Singers (SingerId, FirstName, LastName) VALUES (@id, @firstName, @lastName) THEN RETURN FullName',
params:{
id:18,
firstName:'Virginia',
lastName:'Watson',
},
});
constrowCount=Math.floor(stats[stats.rowCount ]);
console.log(
`Successfully inserted ${rowCount} record into the Singers table.`,
);
rows.forEach(row=>{
console.log(row.toJSON().FullName);
});
awaittransaction.commit();
}catch(err){
console.error('ERROR:',err);
}finally{
// Close the database when finished.
database.close();
}
});
}
insertUsingDmlReturning(instanceId,databaseId);PHP
use Google\Cloud\Spanner\SpannerClient;
/**
* Inserts sample data into the given database using DML returning.
*
* @param string $instanceId The Spanner instance ID.
* @param string $databaseId The Spanner database ID.
*/
function insert_dml_returning(string $instanceId, string $databaseId): void
{
$spanner = new SpannerClient();
$instance = $spanner->instance($instanceId);
$database = $instance->database($databaseId);
// Insert records into SINGERS table and returns the generated column
// FullName of the inserted records using ‘THEN RETURN FullName’. It is also
// possible to return all columns of all the inserted records by using
// ‘THEN RETURN *’.
$sql = 'INSERT INTO Singers (SingerId, FirstName, LastName) '
. "VALUES (12, 'Melissa', 'Garcia'), "
. "(13, 'Russell', 'Morales'), "
. "(14, 'Jacqueline', 'Long'), "
. "(15, 'Dylan', 'Shaw') "
. 'THEN RETURN FullName';
$transaction = $database->transaction();
$result = $transaction->execute($sql);
foreach ($result->rows() as $row) {
printf(
'%s inserted.' . PHP_EOL,
$row['FullName'],
);
}
printf(
'Inserted row(s) count: %d' . PHP_EOL,
$result->stats()['rowCountExact']
);
$transaction->commit();
}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)
# Insert records into the SINGERS table and returns the
# generated column FullName of the inserted records using
# 'THEN RETURN FullName'.
# It is also possible to return all columns of all the
# inserted records by using 'THEN RETURN *'.
definsert_singers(transaction):
results = transaction.execute_sql(
"INSERT INTO Singers (SingerId, FirstName, LastName) VALUES "
"(21, 'Luann', 'Chizoba'), "
"(22, 'Denis', 'Patricio'), "
"(23, 'Felxi', 'Ronan'), "
"(24, 'Dominik', 'Martyna') "
"THEN RETURN FullName"
)
for result in results:
print("FullName: {}".format(*result))
print("{} record(s) inserted.".format(results.stats.row_count_exact))
database.run_in_transaction(insert_singers)Ruby
require"google/cloud/spanner"
##
# This is a snippet for showcasing how to use DML return feature with insert
# operation.
#
# @param project_id [String] The ID of the Google Cloud project.
# @param instance_id [String] The ID of the spanner instance.
# @param database_id [String] The ID of the database.
#
defspanner_insert_dml_returningproject_id:,instance_id:,database_id:
spanner=Google::Cloud::Spanner.newproject:project_id
client=spanner.clientinstance_id,database_id
client.transactiondo|transaction|
# Insert records into the SINGERS table and returns the generated column
# FullName of the inserted records using ‘THEN RETURN FullName’.
# It is also possible to return all columns of all the inserted records
# by using ‘THEN RETURN *’.
results=transaction.execute_query"INSERT INTO Singers (SingerId, FirstName, LastName)
VALUES (12, 'Melissa', 'Garcia'), (13, 'Russell', 'Morales'), (14, 'Jacqueline', 'Long'), (15, 'Dylan', 'Shaw')
THEN RETURN FullName"
results.rows.eachdo|row|
puts"Inserted singers with FullName: #{row[:FullName]}"
end
puts"Inserted row(s) count: #{results.row_count}"
end
end
PostgreSQL
C++
voidInsertUsingDmlReturning(google::cloud::spanner::Clientclient){
//InsertrecordsintoSINGERStableandreturnthegeneratedcolumn
//FullNameoftheinsertedrecordsusing`RETURNINGFullName`.
autocommit=client.Commit(
[&client](google::cloud::spanner::Transactiontxn)
->google::cloud::StatusOr<google::cloud::spanner::Mutations>{
autosql=google::cloud::spanner::SqlStatement(R"""(
INSERT INTO Singers (SingerId, FirstName, LastName)
VALUES (12, 'Melissa', 'Garcia'),
(13, 'Russell', 'Morales'),
(14, 'Jacqueline', 'Long'),
(15, 'Dylan', 'Shaw')
RETURNING FullName
)""");
usingRowType=std::tuple<std::string>;
autorows=client.ExecuteQuery(std::move(txn),std::move(sql));
for(auto&row:google::cloud::spanner::StreamOf<RowType>(rows)){
if(!row)returnstd::move(row).status();
std::cout << "FullName: " << std::get<0>(*row) << "\n";
}
std::cout << "Inserted row(s) count: " << rows.RowsModified() << "\n";
returngoogle::cloud::spanner::Mutations{};
});
if(!commit)throwstd::move(commit).status();
}C#
usingGoogle.Cloud.Spanner.Data ;
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Threading.Tasks;
publicclassInsertUsingDmlReturningAsyncPostgresSample
{
publicasyncTask<List<string>>InsertUsingDmlReturningAsyncPostgres(stringprojectId,stringinstanceId,stringdatabaseId)
{
stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
usingvarconnection=newSpannerConnection (connectionString);
awaitconnection.OpenAsync ();
// Insert records into SINGERS table and return the
// generated column FullName of the inserted records
// using 'RETURNING FullName'.
// It is also possible to return all columns of all the
// inserted records by using 'RETURNING *'.
usingvarcmd=connection.CreateDmlCommand (
@"INSERT INTO Singers(SingerId, FirstName, LastName) VALUES
(6, 'Melissa', 'Garcia'),
(7, 'Russell', 'Morales'),
(8, 'Jacqueline', 'Long'),
(9, 'Dylan', 'Shaw') RETURNING FullName");
varreader=awaitcmd.ExecuteReaderAsync ();
varinsertedSingerNames=newList<string>();
while(awaitreader.ReadAsync ())
{
insertedSingerNames.Add(reader.GetFieldValue<string>("fullname"));
}
Console.WriteLine($"{insertedSingerNames.Count} row(s) inserted...");
returninsertedSingerNames;
}
}Go
import(
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
"google.golang.org/api/iterator"
)
funcpgInsertUsingDMLReturning(wio.Writer,dbstring)error{
ctx:=context.Background()
client,err:=spanner.NewClient(ctx,db)
iferr!=nil{
returnerr
}
deferclient.Close()
// Insert records into the SINGERS table and returns the
// generated column FullName of the inserted records using
// 'RETURNING FullName'.
// It is also possible to return all columns of all the
// inserted records by using 'RETURNING *'.
_,err=client.ReadWriteTransaction(ctx,func(ctxcontext.Context,txn*spanner.ReadWriteTransaction)error{
stmt:=spanner.Statement {
SQL:`INSERT INTO Singers (SingerId, FirstName, LastName)
VALUES (21, 'Melissa', 'Garcia'),
(22, 'Russell', 'Morales'),
(23, 'Jacqueline', 'Long'),
(24, 'Dylan', 'Shaw')
RETURNING FullName`,
}
iter:=txn.Query(ctx,stmt)
deferiter.Stop()
for{
row,err:=iter.Next()
iferr==iterator.Done{
break
}
iferr!=nil{
returnerr
}
varfullNamestring
iferr:=row.Columns (&fullName);err!=nil{
returnerr
}
fmt.Fprintf(w,"%s\n",fullName)
}
fmt.Fprintf(w,"%d record(s) inserted.\n",iter.RowCount)
returnnil
})
returnerr
}
Java
importcom.google.cloud.spanner.DatabaseClient ;
importcom.google.cloud.spanner.DatabaseId ;
importcom.google.cloud.spanner.ResultSet ;
importcom.google.cloud.spanner.Spanner ;
importcom.google.cloud.spanner.SpannerOptions ;
importcom.google.cloud.spanner.Statement ;
publicclass PgInsertUsingDmlReturningSample{
staticvoidinsertUsingDmlReturning(){
// TODO(developer): Replace these variables before running the sample.
finalStringprojectId="my-project";
finalStringinstanceId="my-instance";
finalStringdatabaseId="my-database";
insertUsingDmlReturning(projectId,instanceId,databaseId);
}
staticvoidinsertUsingDmlReturning(StringprojectId,StringinstanceId,StringdatabaseId){
try(Spanner spanner=
SpannerOptions .newBuilder()
.setProjectId(projectId)
.build()
.getService()){
finalDatabaseClient dbClient=
spanner.getDatabaseClient(DatabaseId .of(projectId,instanceId,databaseId));
// Insert records into SINGERS table and returns the
// generated column FullName of the inserted records
// using ‘RETURNING FullName’.
// It is also possible to return all columns of all the
// inserted records by using ‘RETURNING *’.
dbClient
.readWritreadWriteTransaction .run(
transaction->{
Stringsql=
"INSERT INTO Singers (SingerId, FirstName, LastName) VALUES "
+"(12, 'Melissa', 'Garcia'), "
+"(13, 'Russell', 'Morales'), "
+"(14, 'Jacqueline', 'Long'), "
+"(15, 'Dylan', 'Shaw') RETURNING FullName";
// readWriteTransaction.executeQuery(..) API should be used for executing
// DML statements with RETURNING clause.
try(ResultSeResultSetet=transaction.executeQuery(StatemenStatement )){
while(resultSet.next()){
System.out.println(resultSet.getString(0));
}
System.out.printf(
"Inserted row(s) count: %d\n",resultSet.getStats().getRowCountExact());
}
returnnull;
});
}
}
}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
constspanner=newSpanner ({
projectId:projectId,
});
functionpgInsertUsingDmlReturning(instanceId,databaseId){
// Gets a reference to a Cloud Spanner instance and database.
constinstance=spanner.instance(instanceId);
constdatabase=instance.database(databaseId);
database.runTransaction (async(err,transaction)=>{
if(err){
console.error(err);
return;
}
try{
const[rows,stats]=awaittransaction.run({
sql:'INSERT Into Singers (SingerId, FirstName, LastName) VALUES (1,ドル 2,ドル 3ドル) RETURNING FullName',
params:{
p1:18,
p2:'Virginia',
p3:'Watson',
},
});
constrowCount=Math.floor(stats[stats.rowCount ]);
console.log(
`Successfully inserted ${rowCount} record into the Singers table.`,
);
rows.forEach(row=>{
console.log(row.toJSON().fullname);
});
awaittransaction.commit();
}catch(err){
console.error('ERROR:',err);
}finally{
// Close the database when finished.
database.close();
}
});
}
pgInsertUsingDmlReturning(instanceId,databaseId);PHP
use Google\Cloud\Spanner\SpannerClient;
/**
* Inserts sample data into the given postgresql database using DML returning.
*
* @param string $instanceId The Spanner instance ID.
* @param string $databaseId The Spanner database ID.
*/
function pg_insert_dml_returning(string $instanceId, string $databaseId): void
{
$spanner = new SpannerClient();
$instance = $spanner->instance($instanceId);
$database = $instance->database($databaseId);
// Insert records into SINGERS table and returns the generated column
// FullName of the inserted records using ‘RETURNING FullName’. It is also
// possible to return all columns of all the inserted records by using
// ‘RETURNING *’.
$sql = 'INSERT INTO Singers (Singerid, FirstName, LastName) '
. "VALUES (12, 'Melissa', 'Garcia'), "
. "(13, 'Russell', 'Morales'), "
. "(14, 'Jacqueline', 'Long'), "
. "(15, 'Dylan', 'Shaw') "
. 'RETURNING FullName';
$transaction = $database->transaction();
$result = $transaction->execute($sql);
foreach ($result->rows() as $row) {
printf(
'%s inserted.' . PHP_EOL,
$row['fullname'],
);
}
printf(
'Inserted row(s) count: %d' . PHP_EOL,
$result->stats()['rowCountExact']
);
$transaction->commit();
}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)
# Insert records into the SINGERS table and returns the
# generated column FullName of the inserted records using
# 'RETURNING FullName'.
# It is also possible to return all columns of all the
# inserted records by using 'RETURNING *'.
definsert_singers(transaction):
results = transaction.execute_sql(
"INSERT INTO Singers (SingerId, FirstName, LastName) VALUES "
"(21, 'Luann', 'Chizoba'), "
"(22, 'Denis', 'Patricio'), "
"(23, 'Felxi', 'Ronan'), "
"(24, 'Dominik', 'Martyna') "
"RETURNING FullName"
)
for result in results:
print("FullName: {}".format(*result))
print("{} record(s) inserted.".format(results.stats.row_count_exact))
database.run_in_transaction(insert_singers)Ruby
require"google/cloud/spanner"
##
# This is a snippet for showcasing how to use DML return feature with insert
# operation in PostgreSql.
#
# @param project_id [String] The ID of the Google Cloud project.
# @param instance_id [String] The ID of the spanner instance.
# @param database_id [String] The ID of the database.
#
defspanner_postgresql_insert_dml_returningproject_id:,instance_id:,database_id:
spanner=Google::Cloud::Spanner.newproject:project_id
client=spanner.clientinstance_id,database_id
client.transactiondo|transaction|
# Insert records into SINGERS table and returns the generated column
# FullName of the inserted records using ‘RETURNING FullName’.
# It is also possible to return all columns of all the inserted
# records by using ‘RETURNING *’.
results=transaction.execute_query"INSERT INTO Singers (SingerId, FirstName, LastName)
VALUES (12, 'Melissa', 'Garcia'), (13, 'Russell', 'Morales'), (14, 'Jacqueline', 'Long'), (15, 'Dylan', 'Shaw')
RETURNING FullName"
results.rows.eachdo|row|
puts"Inserted singers with FullName: #{row[:fullname]}"
end
puts"Inserted row(s) count: #{results.row_count}"
end
end
The following code example updates the MarketingBudget column of the Albums
table based on a WHERE clause, and it returns the modified MarketingBudget
column of the updated records.
GoogleSQL
C++
voidUpdateUsingDmlReturning(google::cloud::spanner::Clientclient){
//UpdateMarketingBudgetcolumnforrecordssatisfyingaparticular
//conditionandreturnthemodifiedMarketingBudgetcolumnofthe
//updatedrecordsusing`THEN RETURN MarketingBudget`.
autocommit=client.Commit(
[&client](google::cloud::spanner::Transactiontxn)
->google::cloud::StatusOr<google::cloud::spanner::Mutations>{
autosql=google::cloud::spanner::SqlStatement(R"""(
UPDATE Albums SET MarketingBudget = MarketingBudget * 2
WHERE SingerId = 1 AND AlbumId = 1
THEN RETURN MarketingBudget
)""");
usingRowType=std::tuple<absl::optional<std::int64_t>>;
autorows=client.ExecuteQuery(std::move(txn),std::move(sql));
//Note:Thismutatormightbere-run,oritseffectsdiscarded,so
//changingnon-transactionalstate(e.g.,byproducingoutput)is,
//ingeneral,notsomethingtobeimitated.
for(auto&row:google::cloud::spanner::StreamOf<RowType>(rows)){
if(!row)returnstd::move(row).status();
std::cout << "MarketingBudget: ";
if(std::get<0>(*row).has_value()){
std::cout << *std::get<0>(*row);
}else{
std::cout << "NULL";
}
std::cout << "\n";
}
std::cout << "Updated row(s) count: " << rows.RowsModified() << "\n";
returngoogle::cloud::spanner::Mutations{};
});
if(!commit)throwstd::move(commit).status();
}C#
usingGoogle.Cloud.Spanner.Data ;
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Threading.Tasks;
publicclassUpdateUsingDmlReturningAsyncSample
{
publicasyncTask<List<long>>UpdateUsingDmlReturningAsync(stringprojectId,stringinstanceId,stringdatabaseId)
{
stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
usingvarconnection=newSpannerConnection (connectionString);
awaitconnection.OpenAsync ();
// Update MarketingBudget column for records satisfying
// a particular condition and return the modified
// MarketingBudget column of the updated records using
// 'THEN RETURN MarketingBudget'.
// It is also possible to return all columns of all the
// updated records by using 'THEN RETURN *'.
usingvarcmd=connection.CreateDmlCommand ("UPDATE Albums SET MarketingBudget = MarketingBudget * 2 WHERE SingerId = 1 and AlbumId = 1 THEN RETURN MarketingBudget");
varreader=awaitcmd.ExecuteReaderAsync ();
varupdatedMarketingBudgets=newList<long>();
while(awaitreader.ReadAsync ())
{
updatedMarketingBudgets.Add(reader.GetFieldValue<long>("MarketingBudget"));
}
Console.WriteLine($"{updatedMarketingBudgets.Count} row(s) updated...");
returnupdatedMarketingBudgets;
}
}Go
import(
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
"google.golang.org/api/iterator"
)
funcupdateUsingDMLReturning(wio.Writer,dbstring)error{
ctx:=context.Background()
client,err:=spanner.NewClient(ctx,db)
iferr!=nil{
returnerr
}
deferclient.Close()
// Update MarketingBudget column for records satisfying
// a particular condition and returns the modified
// MarketingBudget column of the updated records using
// 'THEN RETURN MarketingBudget'.
// It is also possible to return all columns of all the
// updated records by using 'THEN RETURN *'.
_,err=client.ReadWriteTransaction(ctx,func(ctxcontext.Context,txn*spanner.ReadWriteTransaction)error{
stmt:=spanner.Statement {
SQL:`UPDATE Albums
SET MarketingBudget = MarketingBudget * 2
WHERE SingerId = 1 and AlbumId = 1
THEN RETURN MarketingBudget`,
}
iter:=txn.Query(ctx,stmt)
deferiter.Stop()
for{
row,err:=iter.Next()
iferr==iterator.Done{
break
}
iferr!=nil{
returnerr
}
varmarketingBudgetint64
iferr:=row.Columns (&marketingBudget);err!=nil{
returnerr
}
fmt.Fprintf(w,"%d\n",marketingBudget)
}
fmt.Fprintf(w,"%d record(s) updated.\n",iter.RowCount)
returnnil
})
returnerr
}
Java
importcom.google.cloud.spanner.DatabaseClient ;
importcom.google.cloud.spanner.DatabaseId ;
importcom.google.cloud.spanner.ResultSet ;
importcom.google.cloud.spanner.Spanner ;
importcom.google.cloud.spanner.SpannerOptions ;
importcom.google.cloud.spanner.Statement ;
publicclass UpdateUsingDmlReturningSample{
staticvoidupdateUsingDmlReturning(){
// TODO(developer): Replace these variables before running the sample.
finalStringprojectId="my-project";
finalStringinstanceId="my-instance";
finalStringdatabaseId="my-database";
updateUsingDmlReturning(projectId,instanceId,databaseId);
}
staticvoidupdateUsingDmlReturning(StringprojectId,StringinstanceId,StringdatabaseId){
try(Spanner spanner=
SpannerOptions .newBuilder()
.setProjectId(projectId)
.build()
.getService()){
finalDatabaseClient dbClient=
spanner.getDatabaseClient(DatabaseId .of(projectId,instanceId,databaseId));
// Update MarketingBudget column for records satisfying
// a particular condition and returns the modified
// MarketingBudget column of the updated records using
// ‘THEN RETURN MarketingBudget’.
// It is also possible to return all columns of all the
// updated records by using ‘THEN RETURN *’.
dbClient
.readWritreadWriteTransaction .run(
transaction->{
Stringsql=
"UPDATE Albums "
+"SET MarketingBudget = MarketingBudget * 2 "
+"WHERE SingerId = 1 and AlbumId = 1 "
+"THEN RETURN MarketingBudget";
// readWriteTransaction.executeQuery(..) API should be used for executing
// DML statements with RETURNING clause.
try(ResultSeResultSetet=transaction.executeQuery(StatemenStatement )){
while(resultSet.next()){
System.out.printf("%d\n",resultSet.getLong(0));
}
System.out.printf(
"Updated row(s) count: %d\n",resultSet.getStats().getRowCountExact());
}
returnnull;
});
}
}
}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
constspanner=newSpanner ({
projectId:projectId,
});
functionupdateUsingDmlReturning(instanceId,databaseId){
// Gets a reference to a Cloud Spanner instance and database.
constinstance=spanner.instance(instanceId);
constdatabase=instance.database(databaseId);
database.runTransaction (async(err,transaction)=>{
if(err){
console.error(err);
return;
}
try{
const[rows,stats]=awaittransaction.run({
sql:'UPDATE Albums SET MarketingBudget = 2000000 WHERE SingerId = 1 and AlbumId = 1 THEN RETURN MarketingBudget',
});
constrowCount=Math.floor(stats[stats.rowCount ]);
console.log(
`Successfully updated ${rowCount} record into the Albums table.`,
);
rows.forEach(row=>{
console.log(row.toJSON().MarketingBudget);
});
awaittransaction.commit();
}catch(err){
console.error('ERROR:',err);
}finally{
// Close the database when finished.
database.close();
}
});
}
updateUsingDmlReturning(instanceId,databaseId);PHP
use Google\Cloud\Spanner\SpannerClient;
/**
* Update the given database using DML returning.
*
* @param string $instanceId The Spanner instance ID.
* @param string $databaseId The Spanner database ID.
*/
function update_dml_returning(string $instanceId, string $databaseId): void
{
$spanner = new SpannerClient();
$instance = $spanner->instance($instanceId);
$database = $instance->database($databaseId);
$transaction = $database->transaction();
// Update MarketingBudget column for records satisfying a particular
// condition and returns the modified MarketingBudget column of the updated
// records using ‘THEN RETURN MarketingBudget’. It is also possible to return
// all columns of all the updated records by using ‘THEN RETURN *’.
$result = $transaction->execute(
'UPDATE Albums '
. 'SET MarketingBudget = MarketingBudget * 2 '
. 'WHERE SingerId = 1 and AlbumId = 1 '
. 'THEN RETURN MarketingBudget'
);
foreach ($result->rows() as $row) {
printf('MarketingBudget: %s' . PHP_EOL, $row['MarketingBudget']);
}
printf(
'Updated row(s) count: %d' . PHP_EOL,
$result->stats()['rowCountExact']
);
$transaction->commit();
}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)
# Update MarketingBudget column for records satisfying
# a particular condition and returns the modified
# MarketingBudget column of the updated records using
# 'THEN RETURN MarketingBudget'.
# It is also possible to return all columns of all the
# updated records by using 'THEN RETURN *'.
defupdate_albums(transaction):
results = transaction.execute_sql(
"UPDATE Albums "
"SET MarketingBudget = MarketingBudget * 2 "
"WHERE SingerId = 1 and AlbumId = 1 "
"THEN RETURN MarketingBudget"
)
for result in results:
print("MarketingBudget: {}".format(*result))
print("{} record(s) updated.".format(results.stats.row_count_exact))
database.run_in_transaction(update_albums)Ruby
require"google/cloud/spanner"
##
# This is a snippet for showcasing how to use DML return feature with update
# operation.
#
# @param project_id [String] The ID of the Google Cloud project.
# @param instance_id [String] The ID of the spanner instance.
# @param database_id [String] The ID of the database.
#
defspanner_update_dml_returningproject_id:,instance_id:,database_id:
spanner=Google::Cloud::Spanner.newproject:project_id
client=spanner.clientinstance_id,database_id
client.transactiondo|transaction|
# Update MarketingBudget column for records satisfying a particular
# condition and returns the modified MarketingBudget column of the
# updated records using ‘THEN RETURN MarketingBudget’.
#
# It is also possible to return all columns of all the updated records
# by using ‘THEN RETURN *’.
results=transaction.execute_query"UPDATE Albums SET MarketingBudget = MarketingBudget * 2
WHERE SingerId = 1 and AlbumId = 1
THEN RETURN MarketingBudget"
results.rows.eachdo|row|
puts"Updated Album with MarketingBudget: #{row[:MarketingBudget]}"
end
puts"Updated row(s) count: #{results.row_count}"
end
end
PostgreSQL
C++
voidUpdateUsingDmlReturning(google::cloud::spanner::Clientclient){
//UpdateMarketingBudgetcolumnforrecordssatisfyingaparticular
//conditionandreturnthemodifiedMarketingBudgetcolumnofthe
//updatedrecordsusing`RETURNINGMarketingBudget`.
autocommit=client.Commit(
[&client](google::cloud::spanner::Transactiontxn)
->google::cloud::StatusOr<google::cloud::spanner::Mutations>{
autosql=google::cloud::spanner::SqlStatement(R"""(
UPDATE Albums SET MarketingBudget = MarketingBudget * 2
WHERE SingerId = 1 AND AlbumId = 1
RETURNING MarketingBudget
)""");
usingRowType=std::tuple<absl::optional<std::int64_t>>;
autorows=client.ExecuteQuery(std::move(txn),std::move(sql));
for(auto&row:google::cloud::spanner::StreamOf<RowType>(rows)){
if(!row)returnstd::move(row).status();
std::cout << "MarketingBudget: ";
if(std::get<0>(*row).has_value()){
std::cout << *std::get<0>(*row);
}else{
std::cout << "NULL";
}
std::cout << "\n";
}
std::cout << "Updated row(s) count: " << rows.RowsModified() << "\n";
returngoogle::cloud::spanner::Mutations{};
});
if(!commit)throwstd::move(commit).status();
}C#
usingGoogle.Cloud.Spanner.Data ;
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Threading.Tasks;
publicclassUpdateUsingDmlReturningAsyncPostgresSample
{
publicasyncTask<List<long>>UpdateUsingDmlReturningAsyncPostgres(stringprojectId,stringinstanceId,stringdatabaseId)
{
stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
usingvarconnection=newSpannerConnection (connectionString);
awaitconnection.OpenAsync ();
// Update MarketingBudget column for records satisfying
// a particular condition and return the modified
// MarketingBudget column of the updated records using
// 'RETURNING MarketingBudget'.
// It is also possible to return all columns of all the
// updated records by using 'RETURNING *'.
usingvarcmd=connection.CreateDmlCommand ("UPDATE Albums SET MarketingBudget = MarketingBudget * 2 WHERE SingerId = 14 and AlbumId = 20 RETURNING MarketingBudget");
varreader=awaitcmd.ExecuteReaderAsync ();
varupdatedMarketingBudgets=newList<long>();
while(awaitreader.ReadAsync ())
{
updatedMarketingBudgets.Add(reader.GetFieldValue<long>("marketingbudget"));
}
Console.WriteLine($"{updatedMarketingBudgets.Count} row(s) updated...");
returnupdatedMarketingBudgets;
}
}Go
import(
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
"google.golang.org/api/iterator"
)
funcpgUpdateUsingDMLReturning(wio.Writer,dbstring)error{
ctx:=context.Background()
client,err:=spanner.NewClient(ctx,db)
iferr!=nil{
returnerr
}
deferclient.Close()
// Update MarketingBudget column for records satisfying
// a particular condition and returns the modified
// MarketingBudget column of the updated records using
// 'RETURNING MarketingBudget'.
// It is also possible to return all columns of all the
// updated records by using 'RETURNING *'.
_,err=client.ReadWriteTransaction(ctx,func(ctxcontext.Context,txn*spanner.ReadWriteTransaction)error{
stmt:=spanner.Statement {
SQL:`UPDATE Albums
SET MarketingBudget = MarketingBudget * 2
WHERE SingerId = 1 and AlbumId = 1
RETURNING MarketingBudget`,
}
iter:=txn.Query(ctx,stmt)
deferiter.Stop()
for{
row,err:=iter.Next()
iferr==iterator.Done{
break
}
iferr!=nil{
returnerr
}
varmarketingBudgetint64
iferr:=row.Columns (&marketingBudget);err!=nil{
returnerr
}
fmt.Fprintf(w,"%d\n",marketingBudget)
}
fmt.Fprintf(w,"%d record(s) updated.\n",iter.RowCount)
returnnil
})
returnerr
}
Java
importcom.google.cloud.spanner.DatabaseClient ;
importcom.google.cloud.spanner.DatabaseId ;
importcom.google.cloud.spanner.ResultSet ;
importcom.google.cloud.spanner.Spanner ;
importcom.google.cloud.spanner.SpannerOptions ;
importcom.google.cloud.spanner.Statement ;
publicclass PgUpdateUsingDmlReturningSample{
staticvoidupdateUsingDmlReturning(){
// TODO(developer): Replace these variables before running the sample.
finalStringprojectId="my-project";
finalStringinstanceId="my-instance";
finalStringdatabaseId="my-database";
updateUsingDmlReturning(projectId,instanceId,databaseId);
}
staticvoidupdateUsingDmlReturning(StringprojectId,StringinstanceId,StringdatabaseId){
try(Spanner spanner=
SpannerOptions .newBuilder()
.setProjectId(projectId)
.build()
.getService()){
finalDatabaseClient dbClient=
spanner.getDatabaseClient(DatabaseId .of(projectId,instanceId,databaseId));
// Update MarketingBudget column for records satisfying
// a particular condition and returns the modified
// MarketingBudget column of the updated records using
// ‘RETURNING MarketingBudget’.
// It is also possible to return all columns of all the
// updated records by using ‘RETURNING *’.
dbClient
.readWritreadWriteTransaction .run(
transaction->{
Stringsql=
"UPDATE Albums "
+"SET MarketingBudget = MarketingBudget * 2 "
+"WHERE SingerId = 1 and AlbumId = 1 "
+"RETURNING MarketingBudget";
// readWriteTransaction.executeQuery(..) API should be used for executing
// DML statements with RETURNING clause.
try(ResultSeResultSetet=transaction.executeQuery(StatemenStatement )){
while(resultSet.next()){
System.out.printf("%d\n",resultSet.getLong(0));
}
System.out.printf(
"Updated row(s) count: %d\n",resultSet.getStats().getRowCountExact());
}
returnnull;
});
}
}
}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
constspanner=newSpanner ({
projectId:projectId,
});
functionpgUpdateUsingDmlReturning(instanceId,databaseId){
// Gets a reference to a Cloud Spanner instance and database.
constinstance=spanner.instance(instanceId);
constdatabase=instance.database(databaseId);
database.runTransaction (async(err,transaction)=>{
if(err){
console.error(err);
return;
}
try{
const[rows,stats]=awaittransaction.run({
sql:'UPDATE singers SET FirstName = 1,ドル LastName = 2ドル WHERE singerid = 3ドル RETURNING FullName',
params:{
p1:'Virginia1',
p2:'Watson1',
p3:18,
},
});
constrowCount=Math.floor(stats[stats.rowCount ]);
console.log(
`Successfully updated ${rowCount} record into the Singers table.`,
);
rows.forEach(row=>{
console.log(row.toJSON().fullname);
});
awaittransaction.commit();
}catch(err){
console.error('ERROR:',err);
}finally{
// Close the database when finished.
database.close();
}
});
}
pgUpdateUsingDmlReturning(instanceId,databaseId);PHP
use Google\Cloud\Spanner\SpannerClient;
/**
* Update the given postgresql database using DML returning.
*
* @param string $instanceId The Spanner instance ID.
* @param string $databaseId The Spanner database ID.
*/
function pg_update_dml_returning(string $instanceId, string $databaseId): void
{
$spanner = new SpannerClient();
$instance = $spanner->instance($instanceId);
$database = $instance->database($databaseId);
$transaction = $database->transaction();
// Update MarketingBudget column for records satisfying a particular
// condition and returns the modified MarketingBudget column of the updated
// records using ‘RETURNING MarketingBudget’. It is also possible to return
// all columns of all the updated records by using ‘RETURNING *’.
$result = $transaction->execute(
'UPDATE Albums '
. 'SET MarketingBudget = MarketingBudget * 2 '
. 'WHERE SingerId = 1 and AlbumId = 1 '
. 'RETURNING MarketingBudget'
);
foreach ($result->rows() as $row) {
printf('MarketingBudget: %s' . PHP_EOL, $row['marketingbudget']);
}
printf(
'Updated row(s) count: %d' . PHP_EOL,
$result->stats()['rowCountExact']
);
$transaction->commit();
}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)
# Update MarketingBudget column for records satisfying
# a particular condition and returns the modified
# MarketingBudget column of the updated records using
# 'RETURNING MarketingBudget'.
# It is also possible to return all columns of all the
# updated records by using 'RETURNING *'.
defupdate_albums(transaction):
results = transaction.execute_sql(
"UPDATE Albums "
"SET MarketingBudget = MarketingBudget * 2 "
"WHERE SingerId = 1 and AlbumId = 1 "
"RETURNING MarketingBudget"
)
for result in results:
print("MarketingBudget: {}".format(*result))
print("{} record(s) updated.".format(results.stats.row_count_exact))
database.run_in_transaction(update_albums)Ruby
require"google/cloud/spanner"
##
# This is a snippet for showcasing how to use DML return feature with update
# operation in PostgreSql.
#
# @param project_id [String] The ID of the Google Cloud project.
# @param instance_id [String] The ID of the spanner instance.
# @param database_id [String] The ID of the database.
#
defspanner_postgresql_update_dml_returningproject_id:,instance_id:,database_id:
spanner=Google::Cloud::Spanner.newproject:project_id
client=spanner.clientinstance_id,database_id
client.transactiondo|transaction|
# Update MarketingBudget column for records satisfying a particular
# condition and returns the modified MarketingBudget column of the
# updated records using ‘RETURNING MarketingBudget’.
# It is also possible to return all columns of all the updated records
# by using ‘RETURNING *’.
results=transaction.execute_query"UPDATE Albums SET MarketingBudget = MarketingBudget * 2
WHERE SingerId = 1 and AlbumId = 1
RETURNING MarketingBudget"
results.rows.eachdo|row|
puts"Updated Albums with MarketingBudget: #{row[:marketingbudget]}"
end
puts"Updated row(s) count: #{results.row_count}"
end
end
The following code example deletes all the rows in the Singers table where the
FirstName column is Alice, and it returns the SingerId and FullName
column of the deleted records.
GoogleSQL
C++
voidDeleteUsingDmlReturning(google::cloud::spanner::Clientclient){
//DeleterecordsfromSINGERStablesatisfyingaparticularcondition
//andreturntheSingerIdandFullNamecolumnofthedeletedrecords
//using`THEN RETURN SingerId, FullName'.
auto commit = client.Commit(
[&client](google::cloud::spanner::Transaction txn)
-> google::cloud::StatusOr<google::cloud::spanner::Mutations> {
auto sql = google::cloud::spanner::SqlStatement(R"""(
DELETE FROM Singers
WHERE FirstName = 'Alice'
THEN RETURN SingerId, FullName
)""");
using RowType = std::tuple<std::int64_t, std::string>;
auto rows = client.ExecuteQuery(std::move(txn), std::move(sql));
// Note: This mutator might be re-run, or its effects discarded, so
// changing non-transactional state (e.g., by producing output) is,
// in general, not something to be imitated.
for (auto& row : google::cloud::spanner::StreamOf<RowType>(rows)) {
if (!row) return std::move(row).status();
std::cout << "SingerId: " << std::get<0>(*row) << " ";
std::cout << "FullName: " << std::get<1>(*row) << "\n";
}
std::cout << "Deleted row(s) count: " << rows.RowsModified() << "\n";
return google::cloud::spanner::Mutations{};
});
if (!commit) throw std::move(commit).status();
}C#
usingGoogle.Cloud.Spanner.Data ;
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Threading;
usingSystem.Threading.Tasks;
publicclassDeleteUsingDmlReturningAsyncSample
{
publicasyncTask<List<string>>DeleteUsingDmlReturningAsync(stringprojectId,stringinstanceId,stringdatabaseId)
{
stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
usingvarconnection=newSpannerConnection (connectionString);
awaitconnection.OpenAsync ();
// Delete records from SINGERS table satisfying a
// particular condition and return the SingerId
// and FullName column of the deleted records using
// 'THEN RETURN SingerId, FullName'.
// It is also possible to return all columns of all the
// deleted records by using 'THEN RETURN *'.
usingvarcmd=connection.CreateDmlCommand ("DELETE FROM Singers WHERE FirstName = 'Alice' THEN RETURN SingerId, FullName");
varreader=awaitcmd.ExecuteReaderAsync ();
vardeletedSingerNames=newList<string>();
while(awaitreader.ReadAsync ())
{
deletedSingerNames.Add(reader.GetFieldValue<string>("FullName"));
}
Console.WriteLine($"{deletedSingerNames.Count} row(s) deleted...");
returndeletedSingerNames;
}
}Go
import(
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
"google.golang.org/api/iterator"
)
funcdeleteUsingDMLReturning(wio.Writer,dbstring)error{
ctx:=context.Background()
client,err:=spanner.NewClient(ctx,db)
iferr!=nil{
returnerr
}
deferclient.Close()
// Delete records from SINGERS table satisfying a
// particular condition and returns the SingerId
// and FullName column of the deleted records using
// 'THEN RETURN SingerId, FullName'.
// It is also possible to return all columns of all the
// deleted records by using 'THEN RETURN *'.
_,err=client.ReadWriteTransaction(ctx,func(ctxcontext.Context,txn*spanner.ReadWriteTransaction)error{
stmt:=spanner.Statement {
SQL:`DELETE FROM Singers WHERE FirstName = 'Alice'
THEN RETURN SingerId, FullName`,
}
iter:=txn.Query(ctx,stmt)
deferiter.Stop()
for{
row,err:=iter.Next()
iferr==iterator.Done{
break
}
iferr!=nil{
returnerr
}
var(
singerIDint64
fullNamestring
)
iferr:=row.Columns (&singerID,&fullName);err!=nil{
returnerr
}
fmt.Fprintf(w,"%d %s\n",singerID,fullName)
}
fmt.Fprintf(w,"%d record(s) deleted.\n",iter.RowCount)
returnnil
})
returnerr
}
Java
importcom.google.cloud.spanner.DatabaseClient ;
importcom.google.cloud.spanner.DatabaseId ;
importcom.google.cloud.spanner.ResultSet ;
importcom.google.cloud.spanner.Spanner ;
importcom.google.cloud.spanner.SpannerOptions ;
importcom.google.cloud.spanner.Statement ;
publicclass DeleteUsingDmlReturningSample{
staticvoiddeleteUsingDmlReturningSample(){
// TODO(developer): Replace these variables before running the sample.
finalStringprojectId="my-project";
finalStringinstanceId="my-instance";
finalStringdatabaseId="my-database";
deleteUsingDmlReturningSample(projectId,instanceId,databaseId);
}
staticvoiddeleteUsingDmlReturningSample(
StringprojectId,StringinstanceId,StringdatabaseId){
try(Spanner spanner=
SpannerOptions .newBuilder()
.setProjectId(projectId)
.build()
.getService()){
finalDatabaseClient dbClient=
spanner.getDatabaseClient(DatabaseId .of(projectId,instanceId,databaseId));
// Delete records from SINGERS table satisfying a
// particular condition and returns the SingerId
// and FullName column of the deleted records using
// ‘THEN RETURN SingerId, FullName’.
// It is also possible to return all columns of all the
// deleted records by using ‘THEN RETURN *’.
dbClient
.readWritreadWriteTransaction .run(
transaction->{
Stringsql=
"DELETE FROM Singers WHERE FirstName = 'Alice' THEN RETURN SingerId, FullName";
// readWriteTransaction.executeQuery(..) API should be used for executing
// DML statements with RETURNING clause.
try(ResultSeResultSetet=transaction.executeQuery(StatemenStatement )){
while(resultSet.next()){
System.out.printf("%d %s\n",resultSet.getLong(0),resultSet.getString(1));
}
System.out.printf(
"Deleted row(s) count: %d\n",resultSet.getStats().getRowCountExact());
}
returnnull;
});
}
}
}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
constspanner=newSpanner ({
projectId:projectId,
});
functiondeleteUsingDmlReturning(instanceId,databaseId){
// Gets a reference to a Cloud Spanner instance and database.
constinstance=spanner.instance(instanceId);
constdatabase=instance.database(databaseId);
database.runTransaction (async(err,transaction)=>{
if(err){
console.error(err);
return;
}
try{
const[rows,stats]=awaittransaction.run({
sql:'DELETE FROM Singers WHERE SingerId = 18 THEN RETURN FullName',
});
constrowCount=Math.floor(stats[stats.rowCount ]);
console.log(
`Successfully deleted ${rowCount} record from the Singers table.`,
);
rows.forEach(row=>{
console.log(row.toJSON().FullName);
});
awaittransaction.commit();
}catch(err){
console.error('ERROR:',err);
}finally{
// Close the database when finished.
database.close();
}
});
}
deleteUsingDmlReturning(instanceId,databaseId);PHP
use Google\Cloud\Spanner\SpannerClient;
/**
* Delete data from the given database using DML returning.
*
* @param string $instanceId The Spanner instance ID.
* @param string $databaseId The Spanner database ID.
*/
function delete_dml_returning(string $instanceId, string $databaseId): void
{
$spanner = new SpannerClient();
$instance = $spanner->instance($instanceId);
$database = $instance->database($databaseId);
$transaction = $database->transaction();
// Delete records from SINGERS table satisfying a particular condition and
// returns the SingerId and FullName column of the deleted records using
// 'THEN RETURN SingerId, FullName'. It is also possible to return all columns
// of all the deleted records by using 'THEN RETURN *'.
$result = $transaction->execute(
"DELETE FROM Singers WHERE FirstName = 'Alice' "
. 'THEN RETURN SingerId, FullName',
);
foreach ($result->rows() as $row) {
printf(
'%d %s.' . PHP_EOL,
$row['SingerId'],
$row['FullName']
);
}
printf(
'Deleted row(s) count: %d' . PHP_EOL,
$result->stats()['rowCountExact']
);
$transaction->commit();
}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)
# Delete records from SINGERS table satisfying a
# particular condition and returns the SingerId
# and FullName column of the deleted records using
# 'THEN RETURN SingerId, FullName'.
# It is also possible to return all columns of all the
# deleted records by using 'THEN RETURN *'.
defdelete_singers(transaction):
results = transaction.execute_sql(
"DELETE FROM Singers WHERE FirstName = 'David' "
"THEN RETURN SingerId, FullName"
)
for result in results:
print("SingerId: {}, FullName: {}".format(*result))
print("{} record(s) deleted.".format(results.stats.row_count_exact))
database.run_in_transaction(delete_singers)Ruby
require"google/cloud/spanner"
##
# This is a snippet for showcasing how to use DML return feature with delete
# operation.
#
# @param project_id [String] The ID of the Google Cloud project.
# @param instance_id [String] The ID of the spanner instance.
# @param database_id [String] The ID of the database.
#
defspanner_delete_dml_returningproject_id:,instance_id:,database_id:
spanner=Google::Cloud::Spanner.newproject:project_id
client=spanner.clientinstance_id,database_id
client.transactiondo|transaction|
# Delete records from SINGERS table satisfying a particular condition and
# returns the SingerId and FullName column of the deleted records using
# ‘THEN RETURN SingerId, FullName’.
# It is also possible to return all columns of all the deleted records
# by using ‘THEN RETURN *’.
results=transaction.execute_query"DELETE FROM Singers WHERE FirstName = 'Alice' THEN RETURN SingerId, FullName"
results.rows.eachdo|row|
puts"Deleted singer with SingerId: #{row[:SingerId]}, FullName: #{row[:FullName]}"
end
puts"Deleted row(s) count: #{results.row_count}"
end
end
PostgreSQL
C++
voidDeleteUsingDmlReturning(google::cloud::spanner::Clientclient){
//DeleterecordsfromSINGERStablesatisfyingaparticularcondition
//andreturntheSingerIdandFullNamecolumnofthedeletedrecords
//using`RETURNINGSingerId,FullName'.
auto commit = client.Commit(
[&client](google::cloud::spanner::Transaction txn)
-> google::cloud::StatusOr<google::cloud::spanner::Mutations> {
auto sql = google::cloud::spanner::SqlStatement(R"""(
DELETE FROM Singers
WHERE FirstName = 'Alice'
RETURNING SingerId, FullName
)""");
using RowType = std::tuple<std::int64_t, std::string>;
auto rows = client.ExecuteQuery(std::move(txn), std::move(sql));
for (auto& row : google::cloud::spanner::StreamOf<RowType>(rows)) {
if (!row) return std::move(row).status();
std::cout << "SingerId: " << std::get<0>(*row) << " ";
std::cout << "FullName: " << std::get<1>(*row) << "\n";
}
std::cout << "Deleted row(s) count: " << rows.RowsModified() << "\n";
return google::cloud::spanner::Mutations{};
});
if (!commit) throw std::move(commit).status();
}C#
usingGoogle.Cloud.Spanner.Data ;
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Threading.Tasks;
publicclassDeleteUsingDmlReturningAsyncPostgresSample
{
publicasyncTask<List<string>>DeleteUsingDmlReturningAsyncPostgres(stringprojectId,stringinstanceId,stringdatabaseId)
{
stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
usingvarconnection=newSpannerConnection (connectionString);
awaitconnection.OpenAsync ();
// Delete records from SINGERS table satisfying a
// particular condition and return the SingerId
// and FullName column of the deleted records using
// 'RETURNING SingerId, FullName'.
// It is also possible to return all columns of all the
// deleted records by using 'RETURNING *'.
usingvarcmd=connection.CreateDmlCommand ("DELETE FROM Singers WHERE FirstName = 'Lata' RETURNING SingerId, FullName");
varreader=awaitcmd.ExecuteReaderAsync ();
vardeletedSingerNames=newList<string>();
while(awaitreader.ReadAsync ())
{
deletedSingerNames.Add(reader.GetFieldValue<string>("fullname"));
}
Console.WriteLine($"{deletedSingerNames.Count} row(s) deleted...");
returndeletedSingerNames;
}
}Go
import(
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
"google.golang.org/api/iterator"
)
funcpgDeleteUsingDMLReturning(wio.Writer,dbstring)error{
ctx:=context.Background()
client,err:=spanner.NewClient(ctx,db)
iferr!=nil{
returnerr
}
deferclient.Close()
// Delete records from SINGERS table satisfying a
// particular condition and returns the SingerId
// and FullName column of the deleted records using
// 'RETURNING SingerId, FullName'.
// It is also possible to return all columns of all the
// deleted records by using 'RETURNING *'.
_,err=client.ReadWriteTransaction(ctx,func(ctxcontext.Context,txn*spanner.ReadWriteTransaction)error{
stmt:=spanner.Statement {
SQL:`DELETE FROM Singers WHERE FirstName = 'Alice'
RETURNING SingerId, FullName`,
}
iter:=txn.Query(ctx,stmt)
deferiter.Stop()
for{
row,err:=iter.Next()
iferr==iterator.Done{
break
}
iferr!=nil{
returnerr
}
var(
singerIDint64
fullNamestring
)
iferr:=row.Columns (&singerID,&fullName);err!=nil{
returnerr
}
fmt.Fprintf(w,"%d %s\n",singerID,fullName)
}
fmt.Fprintf(w,"%d record(s) deleted.\n",iter.RowCount)
returnnil
})
returnerr
}
Java
importcom.google.cloud.spanner.DatabaseClient ;
importcom.google.cloud.spanner.DatabaseId ;
importcom.google.cloud.spanner.ResultSet ;
importcom.google.cloud.spanner.Spanner ;
importcom.google.cloud.spanner.SpannerOptions ;
importcom.google.cloud.spanner.Statement ;
publicclass PgDeleteUsingDmlReturningSample{
staticvoiddeleteUsingDmlReturningSample(){
// TODO(developer): Replace these variables before running the sample.
finalStringprojectId="my-project";
finalStringinstanceId="my-instance";
finalStringdatabaseId="my-database";
deleteUsingDmlReturningSample(projectId,instanceId,databaseId);
}
staticvoiddeleteUsingDmlReturningSample(
StringprojectId,StringinstanceId,StringdatabaseId){
try(Spanner spanner=
SpannerOptions .newBuilder()
.setProjectId(projectId)
.build()
.getService()){
finalDatabaseClient dbClient=
spanner.getDatabaseClient(DatabaseId .of(projectId,instanceId,databaseId));
// Delete records from SINGERS table satisfying a
// particular condition and returns the SingerId
// and FullName column of the deleted records using
// ‘RETURNING SingerId, FullName’.
// It is also possible to return all columns of all the
// deleted records by using ‘RETURNING *’.
dbClient
.readWritreadWriteTransaction .run(
transaction->{
Stringsql=
"DELETE FROM Singers WHERE FirstName = 'Alice' RETURNING SingerId, FullName";
// readWriteTransaction.executeQuery(..) API should be used for executing
// DML statements with RETURNING clause.
try(ResultSeResultSetet=transaction.executeQuery(StatemenStatement )){
while(resultSet.next()){
System.out.printf("%d %s\n",resultSet.getLong(0),resultSet.getString(1));
}
System.out.printf(
"Deleted row(s) count: %d\n",resultSet.getStats().getRowCountExact());
}
returnnull;
});
}
}
}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
constspanner=newSpanner ({
projectId:projectId,
});
functionpgDeleteUsingDmlReturning(instanceId,databaseId){
// Gets a reference to a Cloud Spanner instance and database.
constinstance=spanner.instance(instanceId);
constdatabase=instance.database(databaseId);
database.runTransaction (async(err,transaction)=>{
if(err){
console.error(err);
return;
}
try{
const[rows,stats]=awaittransaction.run({
sql:'DELETE FROM Singers WHERE SingerId = 18 RETURNING FullName',
});
constrowCount=Math.floor(stats[stats.rowCount ]);
console.log(
`Successfully deleted ${rowCount} record from the Singers table.`,
);
rows.forEach(row=>{
console.log(row.toJSON().fullname);
});
awaittransaction.commit();
}catch(err){
console.error('ERROR:',err);
}finally{
// Close the database when finished.
database.close();
}
});
}
pgDeleteUsingDmlReturning(instanceId,databaseId);PHP
use Google\Cloud\Spanner\SpannerClient;
/**
* Delete data from the given postgresql database using DML returning.
*
* @param string $instanceId The Spanner instance ID.
* @param string $databaseId The Spanner database ID.
*/
function pg_delete_dml_returning(string $instanceId, string $databaseId): void
{
$spanner = new SpannerClient();
$instance = $spanner->instance($instanceId);
$database = $instance->database($databaseId);
$transaction = $database->transaction();
// Delete records from SINGERS table satisfying a particular condition and
// returns the SingerId and FullName column of the deleted records using
// ‘RETURNING SingerId, FullName’. It is also possible to return all columns
// of all the deleted records by using ‘RETURNING *’.
$result = $transaction->execute(
"DELETE FROM Singers WHERE FirstName = 'Alice' "
. 'RETURNING SingerId, FullName',
);
foreach ($result->rows() as $row) {
printf(
'%d %s.' . PHP_EOL,
$row['singerid'],
$row['fullname']
);
}
printf(
'Deleted row(s) count: %d' . PHP_EOL,
$result->stats()['rowCountExact']
);
$transaction->commit();
}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)
# Delete records from SINGERS table satisfying a
# particular condition and returns the SingerId
# and FullName column of the deleted records using
# 'RETURNING SingerId, FullName'.
# It is also possible to return all columns of all the
# deleted records by using 'RETURNING *'.
defdelete_singers(transaction):
results = transaction.execute_sql(
"DELETE FROM Singers WHERE FirstName = 'David' "
"RETURNING SingerId, FullName"
)
for result in results:
print("SingerId: {}, FullName: {}".format(*result))
print("{} record(s) deleted.".format(results.stats.row_count_exact))
database.run_in_transaction(delete_singers)Ruby
require"google/cloud/spanner"
##
# This is a snippet for showcasing how to use DML return feature with delete
# operation in PostgreSql.
#
# @param project_id [String] The ID of the Google Cloud project.
# @param instance_id [String] The ID of the spanner instance.
# @param database_id [String] The ID of the database.
#
defspanner_postgresql_delete_dml_returningproject_id:,instance_id:,database_id:
spanner=Google::Cloud::Spanner.newproject:project_id
client=spanner.clientinstance_id,database_id
client.transactiondo|transaction|
# Delete records from SINGERS table satisfying a particular condition and
# returns the SingerId and FullName column of the deleted records using
# ‘RETURNING SingerId, FullName’.
# It is also possible to return all columns of all the deleted records
# by using ‘RETURNING *’.
results=transaction.execute_query"DELETE FROM singers WHERE firstname = 'Alice' RETURNING SingerId, FullName"
results.rows.eachdo|row|
puts"Deleted singer with SingerId: #{row[:singerid]}, FullName: #{row[:fullname]}"
end
puts"Deleted row(s) count: #{results.row_count}"
end
end
Read data written in the same transaction
Changes you make using DML statements are visible to subsequent statements in the same transaction. This is different from using mutations, where changes are not visible until the transaction commits.
Spanner checks the constraints after every DML statement. This is different from using mutations, where Spanner buffers mutations in the client until commit and checks constraints at commit time. Evaluating the constraints after each statement allows Spanner to guarantee that the data that a DML statement returns is consistent with the schema.
The following example updates a row in the Singers table, then executes a
SELECT statement to print the new values.
C++
voidDmlWriteThenRead(google::cloud::spanner::Clientclient){
namespacespanner=::google::cloud::spanner;
using::google::cloud::StatusOr;
autocommit_result=client.Commit(
[&client](spanner::Transactiontxn)->StatusOr<spanner::Mutations>{
autoinsert=client.ExecuteDml(
txn,spanner::SqlStatement(
"INSERT INTO Singers (SingerId, FirstName, LastName)"
" VALUES (11, 'Timothy', 'Campbell')"));
if(!insert)returnstd::move(insert).status();
// Read newly inserted record.
spanner::SqlStatementselect(
"SELECT FirstName, LastName FROM Singers where SingerId = 11");
usingRowType=std::tuple<std::string,std::string>;
autorows=client.ExecuteQuery(std::move(txn),std::move(select));
// Note: This mutator might be re-run, or its effects discarded, so
// changing non-transactional state (e.g., by producing output) is,
// in general, not something to be imitated.
for(autoconst&row:spanner::StreamOf<RowType>(rows)){
if(!row)returnstd::move(row).status();
std::cout << "FirstName: " << std::get<0>(*row) << "\t";
std::cout << "LastName: " << std::get<1>(*row) << "\n";
}
returnspanner::Mutations{};
});
if(!commit_result)throwstd::move(commit_result).status();
std::cout << "Write then read succeeded [spanner_dml_write_then_read]\n";
}C#
usingGoogle.Cloud.Spanner.Data ;
usingSystem;
usingSystem.Threading.Tasks;
publicclassWriteAndReadUsingDmlCoreAsyncSample
{
publicasyncTask<int>WriteAndReadUsingDmlCoreAsync(stringprojectId,stringinstanceId,stringdatabaseId)
{
stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
usingvarconnection=newSpannerConnection (connectionString);
awaitconnection.OpenAsync ();
usingvarcreateDmlCmd=connection.CreateDmlCommand (@"INSERT Singers (SingerId, FirstName, LastName) VALUES (11, 'Timothy', 'Campbell')");
introwCount=awaitcreateDmlCmd.ExecuteNonQueryAsync();
Console.WriteLine($"{rowCount} row(s) inserted...");
// Read newly inserted record.
usingvarcreateSelectCmd=connection.CreateSelectCommand (@"SELECT FirstName, LastName FROM Singers WHERE SingerId = 11");
usingvarreader=awaitcreateSelectCmd.ExecuteReaderAsync ();
while(awaitreader.ReadAsync ())
{
Console.WriteLine($"{reader.GetFieldValue<string>("FirstName")} {reader.GetFieldValue<string>("LastName")}");
}
returnrowCount;
}
}Go
import(
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
"google.golang.org/api/iterator"
)
funcwriteAndReadUsingDML(wio.Writer,dbstring)error{
ctx:=context.Background()
client,err:=spanner.NewClient(ctx,db)
iferr!=nil{
returnerr
}
deferclient.Close()
_,err=client.ReadWriteTransaction(ctx,func(ctxcontext.Context,txn*spanner.ReadWriteTransaction)error{
// Insert Record
stmt:=spanner.Statement {
SQL:`INSERT Singers (SingerId, FirstName, LastName)
VALUES (11, 'Timothy', 'Campbell')`,
}
rowCount,err:=txn.Update(ctx,stmt)
iferr!=nil{
returnerr
}
fmt.Fprintf(w,"%d record(s) inserted.\n",rowCount)
// Read newly inserted record
stmt=spanner.Statement {SQL:`SELECT FirstName, LastName FROM Singers WHERE SingerId = 11`}
iter:=txn.Query(ctx,stmt)
deferiter.Stop()
for{
row,err:=iter.Next()
iferr==iterator.Done||err!=nil{
break
}
varfirstName,lastNamestring
iferr:=row.ColumnByName ("FirstName",&firstName);err!=nil{
returnerr
}
iferr:=row.ColumnByName ("LastName",&lastName);err!=nil{
returnerr
}
fmt.Fprintf(w,"Found record name with %s, %s",firstName,lastName)
}
returnerr
})
returnerr
}
Java
staticvoidwriteAndReadUsingDml(DatabaseClientdbClient){
dbClient
.readWriteTransaction()
.run(transaction->{
// Insert record.
Stringsql=
"INSERT INTO Singers (SingerId, FirstName, LastName) "
+" VALUES (11, 'Timothy', 'Campbell')";
longrowCount=transaction.executeUpdate(Statement.of(sql));
System.out.printf("%d record inserted.\n",rowCount);
// Read newly inserted record.
sql="SELECT FirstName, LastName FROM Singers WHERE SingerId = 11";
// We use a try-with-resource block to automatically release resources held by
// ResultSet.
try(ResultSetresultSet=transaction.executeQuery(Statement.of(sql))){
while(resultSet.next()){
System.out.printf(
"%s %s\n",
resultSet.getString("FirstName"),resultSet.getString("LastName"));
}
}
returnnull;
});
}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
constspanner=newSpanner ({
projectId:projectId,
});
// Gets a reference to a Cloud Spanner instance and database
constinstance=spanner.instance(instanceId);
constdatabase=instance.database(databaseId);
database.runTransaction (async(err,transaction)=>{
if(err){
console.error(err);
return;
}
try{
awaittransaction.runUpdate ({
sql:`INSERT Singers (SingerId, FirstName, LastName)
VALUES (11, 'Timothy', 'Campbell')`,
});
const[rows]=awaittransaction.run({
sql:'SELECT FirstName, LastName FROM Singers',
});
rows.forEach(row=>{
constjson=row.toJSON();
console.log(`${json.FirstName}${json.LastName}`);
});
awaittransaction.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\Transaction;
/**
* Writes then reads data inside a Transaction with a DML statement.
*
* 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 write_read_with_dml(string $instanceId, string $databaseId): void
{
$spanner = new SpannerClient();
$instance = $spanner->instance($instanceId);
$database = $instance->database($databaseId);
$database->runTransaction(function (Transaction $t) {
$rowCount = $t->executeUpdate(
'INSERT Singers (SingerId, FirstName, LastName) '
. " VALUES (11, 'Timothy', 'Campbell')");
printf('Inserted %d row(s).' . PHP_EOL, $rowCount);
$results = $t->execute('SELECT FirstName, LastName FROM Singers WHERE SingerId = 11');
foreach ($results as $row) {
printf('%s %s' . PHP_EOL, $row['FirstName'], $row['LastName']);
}
$t->commit();
});
}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)
defwrite_then_read(transaction):
# Insert record.
row_ct = transaction.execute_update(
"INSERT INTO Singers (SingerId, FirstName, LastName) "
" VALUES (11, 'Timothy', 'Campbell')"
)
print("{} record(s) inserted.".format(row_ct))
# Read newly inserted record.
results = transaction.execute_sql(
"SELECT FirstName, LastName FROM Singers WHERE SingerId = 11"
)
for result in results:
print("FirstName: {}, LastName: {}".format(*result))
database.run_in_transaction(write_then_read)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.newproject:project_id
client=spanner.clientinstance_id,database_id
row_count=0
client.transactiondo|transaction|
row_count=transaction.execute_update(
"INSERT INTO Singers (SingerId, FirstName, LastName) VALUES (11, 'Timothy', 'Campbell')"
)
puts"#{row_count} record updated."
transaction.execute("SELECT FirstName, LastName FROM Singers WHERE SingerId = 11").rows.eachdo|row|
puts"#{row[:FirstName]}#{row[:LastName]}"
end
endGet the query plan
You can retrieve a query plan
using the Google Cloud console, the client libraries, and the gcloud
command-line tool.
Use Partitioned DML
Partitioned DML is designed for bulk updates and deletes, particularly periodic cleanup and backfilling.
Execute statements with the Google Cloud CLI
To execute a Partitioned DML statement, use the
gcloud spanner databases execute-sql command with the
--enable-partitioned-dml option. The following example updates rows in the
Albums table.
gcloudspannerdatabasesexecute-sqlexample-db\
--instance=test-instance--enable-partitioned-dml\
--sql='UPDATE Albums SET MarketingBudget = 0 WHERE MarketingBudget IS NULL'
Modify data using the client library
The following code example updates the MarketingBudget column of the Albums
table.
C++
You use the ExecutePartitionedDml() function to execute a Partitioned DML statement.
voidDmlPartitionedUpdate(google::cloud::spanner::Clientclient){
namespacespanner=::google::cloud::spanner;
autoresult=client.ExecutePartitionedDml(
spanner::SqlStatement("UPDATE Albums SET MarketingBudget = 100000"
" WHERE SingerId > 1"));
if(!result)throwstd::move(result).status();
std::cout << "Updated at least " << result->row_count_lower_bound
<< " row(s) [spanner_dml_partitioned_update]\n";
}C#
You use the ExecutePartitionedUpdateAsync() method to execute a Partitioned DML statement.
usingGoogle.Cloud.Spanner.Data ;
usingSystem;
usingSystem.Threading.Tasks;
publicclassUpdateUsingPartitionedDmlCoreAsyncSample
{
publicasyncTask<long>UpdateUsingPartitionedDmlCoreAsync(stringprojectId,stringinstanceId,stringdatabaseId)
{
stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
usingvarconnection=newSpannerConnection (connectionString);
awaitconnection.OpenAsync ();
usingvarcmd=connection.CreateDmlCommand ("UPDATE Albums SET MarketingBudget = 100000 WHERE SingerId > 1");
longrowCount=awaitcmd.ExecutePartitionedUpdateAsync ();
Console.WriteLine($"{rowCount} row(s) updated...");
returnrowCount;
}
}Go
You use the PartitionedUpdate() method to execute a Partitioned DML statement.
import(
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
)
funcupdateUsingPartitionedDML(wio.Writer,dbstring)error{
ctx:=context.Background()
client,err:=spanner.NewClient(ctx,db)
iferr!=nil{
returnerr
}
deferclient.Close()
stmt:=spanner.Statement {SQL:"UPDATE Albums SET MarketingBudget = 100000 WHERE SingerId > 1"}
rowCount,err:=client.PartitionedUpdate(ctx,stmt)
iferr!=nil{
returnerr
}
fmt.Fprintf(w,"%d record(s) updated.\n",rowCount)
returnnil
}
Java
You use the executePartitionedUpdate() method to execute a Partitioned DML statement.
staticvoidupdateUsingPartitionedDml(DatabaseClientdbClient){
Stringsql="UPDATE Albums SET MarketingBudget = 100000 WHERE SingerId > 1";
longrowCount=dbClient.executePartitionedUpdate(Statement.of(sql));
System.out.printf("%d records updated.\n",rowCount);
}Node.js
You use the runPartitionedUpdate() method to execute a Partitioned DML statement.
// 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
constspanner=newSpanner ({
projectId:projectId,
});
// Gets a reference to a Cloud Spanner instance and database
constinstance=spanner.instance(instanceId);
constdatabase=instance.database(databaseId);
try{
const[rowCount]=awaitdatabase.runPartitionedUpdate ({
sql:'UPDATE Albums SET MarketingBudget = 100000 WHERE SingerId > 1',
});
console.log(`Successfully updated ${rowCount} records.`);
}catch(err){
console.error('ERROR:',err);
}finally{
// Close the database when finished.
database.close();
}PHP
You use the executePartitionedUpdate() method to execute a Partitioned DML statement.
use Google\Cloud\Spanner\SpannerClient;
/**
* Updates sample data in the database by partition with a DML statement.
*
* This updates the `MarketingBudget` column which must be created before
* running this sample. You can add the column by running the `add_column`
* sample or by running this DDL statement against your database:
*
* ALTER TABLE Albums ADD COLUMN MarketingBudget INT64
*
* Example:
* ```
* update_data($instanceId, $databaseId);
* ```
*
* @param string $instanceId The Spanner instance ID.
* @param string $databaseId The Spanner database ID.
*/
function update_data_with_partitioned_dml(string $instanceId, string $databaseId): void
{
$spanner = new SpannerClient();
$instance = $spanner->instance($instanceId);
$database = $instance->database($databaseId);
$rowCount = $database->executePartitionedUpdate(
'UPDATE Albums SET MarketingBudget = 100000 WHERE SingerId > 1'
);
printf('Updated %d row(s).' . PHP_EOL, $rowCount);
}Python
You use the execute_partitioned_dml() method to execute a Partitioned DML statement.
# 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)
row_ct = database.execute_partitioned_dml(
"UPDATE Albums SET MarketingBudget = 100000 WHERE SingerId > 1"
)
print("{} records updated.".format(row_ct))Ruby
You use the execute_partitioned_update() method to execute a Partitioned DML statement.
# 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.newproject:project_id
client=spanner.clientinstance_id,database_id
row_count=client.execute_partition_update(
"UPDATE Albums SET MarketingBudget = 100000 WHERE SingerId > 1"
)
puts"#{row_count} records updated."The following code example deletes rows from the Singers table, based on the
SingerId column.
C++
voidDmlPartitionedDelete(google::cloud::spanner::Clientclient){
namespacespanner=::google::cloud::spanner;
autoresult=client.ExecutePartitionedDml(
spanner::SqlStatement("DELETE FROM Singers WHERE SingerId > 10"));
if(!result)throwstd::move(result).status();
std::cout << "Deleted at least " << result->row_count_lower_bound
<< " row(s) [spanner_dml_partitioned_delete]\n";
}C#
usingGoogle.Cloud.Spanner.Data ;
usingSystem;
usingSystem.Threading.Tasks;
publicclassDeleteUsingPartitionedDmlCoreAsyncSample
{
publicasyncTask<long>DeleteUsingPartitionedDmlCoreAsync(stringprojectId,stringinstanceId,stringdatabaseId)
{
stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
usingvarconnection=newSpannerConnection (connectionString);
awaitconnection.OpenAsync ();
usingvarcmd=connection.CreateDmlCommand ("DELETE FROM Singers WHERE SingerId > 10");
longrowCount=awaitcmd.ExecutePartitionedUpdateAsync ();
Console.WriteLine($"{rowCount} row(s) deleted...");
returnrowCount;
}
}Go
import(
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
)
funcdeleteUsingPartitionedDML(wio.Writer,dbstring)error{
ctx:=context.Background()
client,err:=spanner.NewClient(ctx,db)
iferr!=nil{
returnerr
}
deferclient.Close()
stmt:=spanner.Statement {SQL:"DELETE FROM Singers WHERE SingerId > 10"}
rowCount,err:=client.PartitionedUpdate(ctx,stmt)
iferr!=nil{
returnerr
}
fmt.Fprintf(w,"%d record(s) deleted.",rowCount)
returnnil
}
Java
staticvoiddeleteUsingPartitionedDml(DatabaseClientdbClient){
Stringsql="DELETE FROM Singers WHERE SingerId > 10";
longrowCount=dbClient.executePartitionedUpdate(Statement.of(sql));
System.out.printf("%d records deleted.\n",rowCount);
}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
constspanner=newSpanner ({
projectId:projectId,
});
// Gets a reference to a Cloud Spanner instance and database
constinstance=spanner.instance(instanceId);
constdatabase=instance.database(databaseId);
try{
const[rowCount]=awaitdatabase.runPartitionedUpdate ({
sql:'DELETE FROM Singers WHERE SingerId > 10',
});
console.log(`Successfully deleted ${rowCount} records.`);
}catch(err){
console.error('ERROR:',err);
}finally{
// Close the database when finished.
database.close();
}PHP
use Google\Cloud\Spanner\SpannerClient;
/**
* Delete sample data in the database by partition with a DML statement.
*
* This updates the `MarketingBudget` column which must be created before
* running this sample. You can add the column by running the `add_column`
* sample or by running this DDL statement against your database:
*
* ALTER TABLE Albums ADD COLUMN MarketingBudget INT64
*
* Example:
* ```
* update_data($instanceId, $databaseId);
* ```
*
* @param string $instanceId The Spanner instance ID.
* @param string $databaseId The Spanner database ID.
*/
function delete_data_with_partitioned_dml(string $instanceId, string $databaseId): void
{
$spanner = new SpannerClient();
$instance = $spanner->instance($instanceId);
$database = $instance->database($databaseId);
$rowCount = $database->executePartitionedUpdate(
'DELETE FROM Singers WHERE SingerId > 10'
);
printf('Deleted %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)
row_ct = database.execute_partitioned_dml("DELETE FROM Singers WHERE SingerId > 10")
print("{} record(s) deleted.".format(row_ct))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.newproject:project_id
client=spanner.clientinstance_id,database_id
row_count=client.execute_partition_update(
"DELETE FROM Singers WHERE SingerId > 10"
)
puts"#{row_count} records deleted."Use batch DML
If you need to avoid the extra latency incurred from multiple serial requests,
use batch DML to send multiple INSERT, UPDATE, or DELETE statements in a
single transaction:
C++
Use the ExecuteBatchDml() function to execute a list of DML statements.
voidDmlBatchUpdate(google::cloud::spanner::Clientclient){
namespacespanner=::google::cloud::spanner;
autocommit_result=
client.Commit([&client](spanner::Transactionconst&txn)
->google::cloud::StatusOr<spanner::Mutations>{
std::vector<spanner::SqlStatement>statements={
spanner::SqlStatement("INSERT INTO Albums"
" (SingerId, AlbumId, AlbumTitle,"
" MarketingBudget)"
" VALUES (1, 3, 'Test Album Title', 10000)"),
spanner::SqlStatement("UPDATE Albums"
" SET MarketingBudget = MarketingBudget * 2"
" WHERE SingerId = 1 and AlbumId = 3")};
autoresult=client.ExecuteBatchDml(txn,statements);
if(!result)returnstd::move(result).status();
// Note: This mutator might be re-run, or its effects discarded, so
// changing non-transactional state (e.g., by producing output) is,
// in general, not something to be imitated.
for(std::size_ti=0;i < result->stats.size();++i){
std::cout << result->stats[i].row_count << " rows affected"
<< " for the statement " << (i+1) << ".\n";
}
// Batch operations may have partial failures, in which case
// ExecuteBatchDml returns with success, but the application should
// verify that all statements completed successfully
if(!result->status.ok())returnresult->status;
returnspanner::Mutations{};
});
if(!commit_result)throwstd::move(commit_result).status();
std::cout << "Update was successful [spanner_dml_batch_update]\n";
}C#
Use the connection.CreateBatchDmlCommand() method to create your batch
command, use the Add method to add DML statements, and execute the
statements with the ExecuteNonQueryAsync() method.
usingGoogle.Cloud.Spanner.Data ;
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Threading.Tasks;
publicclassUpdateUsingBatchDmlCoreAsyncSample
{
publicasyncTask<int>UpdateUsingBatchDmlCoreAsync(stringprojectId,stringinstanceId,stringdatabaseId)
{
stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
usingvarconnection=newSpannerConnection (connectionString);
awaitconnection.OpenAsync ();
SpannerBatchCommand cmd=connection.CreateBatchDmlCommand();
cmd.Add ("INSERT INTO Albums (SingerId, AlbumId, AlbumTitle, MarketingBudget) VALUES (1, 3, 'Test Album Title', 10000)");
cmd.Add ("UPDATE Albums SET MarketingBudget = MarketingBudget * 2 WHERE SingerId = 1 and AlbumId = 3");
IEnumerable<long>affectedRows=awaitcmd.ExecuteNonQueryAsync ();
Console.WriteLine($"Executed {affectedRows.Count()} "+"SQL statements using Batch DML.");
returnaffectedRows.Count();
}
}Go
Use the BatchUpdate() method to execute an array of DML Statement objects.
import(
"context"
"fmt"
"io"
"cloud.google.com/go/spanner"
)
funcupdateUsingBatchDML(wio.Writer,dbstring)error{
ctx:=context.Background()
client,err:=spanner.NewClient(ctx,db)
iferr!=nil{
returnerr
}
deferclient.Close()
_,err=client.ReadWriteTransaction(ctx,func(ctxcontext.Context,txn*spanner.ReadWriteTransaction)error{
stmts:=[]spanner.Statement {
{SQL:`INSERT INTO Albums
(SingerId, AlbumId, AlbumTitle, MarketingBudget)
VALUES (1, 3, 'Test Album Title', 10000)`},
{SQL:`UPDATE Albums
SET MarketingBudget = MarketingBudget * 2
WHERE SingerId = 1 and AlbumId = 3`},
}
rowCounts,err:=txn.BatchUpdate (ctx,stmts)
iferr!=nil{
returnerr
}
fmt.Fprintf(w,"Executed %d SQL statements using Batch DML.\n",len(rowCounts))
returnnil
})
returnerr
}
Java
Use the transaction.batchUpdate() method to execute an ArrayList of
multiple DML Statement objects.
staticvoidupdateUsingBatchDml(DatabaseClientdbClient){
dbClient
.readWriteTransaction()
.run(transaction->{
List<Statement>stmts=newArrayList<Statement>();
Stringsql=
"INSERT INTO Albums "
+"(SingerId, AlbumId, AlbumTitle, MarketingBudget) "
+"VALUES (1, 3, 'Test Album Title', 10000) ";
stmts.add(Statement.of(sql));
sql=
"UPDATE Albums "
+"SET MarketingBudget = MarketingBudget * 2 "
+"WHERE SingerId = 1 and AlbumId = 3";
stmts.add(Statement.of(sql));
long[]rowCounts;
try{
rowCounts=transaction.batchUpdate(stmts);
}catch(SpannerBatchUpdateExceptione){
rowCounts=e.getUpdateCounts();
}
for(inti=0;i < rowCounts.length;i++){
System.out.printf("%d record updated by stmt %d.\n",rowCounts[i],i);
}
returnnull;
});
}Node.js
Use transaction.batchUpdate() to execute a list of DML statements.
// 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
constspanner=newSpanner ({
projectId:projectId,
});
// Gets a reference to a Cloud Spanner instance and database
constinstance=spanner.instance(instanceId);
constdatabase=instance.database(databaseId);
constinsert={
sql:`INSERT INTO Albums (SingerId, AlbumId, AlbumTitle, MarketingBudget)
VALUES (1, 3, "Test Album Title", 10000)`,
};
constupdate={
sql:`UPDATE Albums SET MarketingBudget = MarketingBudget * 2
WHERE SingerId = 1 and AlbumId = 3`,
};
constdmlStatements=[insert,update];
try{
awaitdatabase.runTransactionAsync (asynctransaction=>{
const[rowCounts]=awaittransaction.batchUpdate(dmlStatements);
awaittransaction.commit();
console.log(
`Successfully executed ${rowCounts.length} SQL statements using Batch DML.`,
);
});
}catch(err){
console.error('ERROR:',err);
throwerr;
}finally{
// Close the database when finished.
database.close();
}PHP
Use executeUpdateBatch() to create a list of DML statements, then use
commit() to execute the statements.
use Google\Cloud\Spanner\SpannerClient;
use Google\Cloud\Spanner\Transaction;
/**
* Updates sample data in the database with Batch DML.
*
* This requires the `MarketingBudget` column which must be created before
* running this sample. You can add the column by running the `add_column`
* sample or by running this DDL statement against your database:
*
* ALTER TABLE Albums ADD COLUMN MarketingBudget INT64
*
* Example:
* ```
* update_data_with_batch_dml($instanceId, $databaseId);
* ```
*
* @param string $instanceId The Spanner instance ID.
* @param string $databaseId The Spanner database ID.
*/
function update_data_with_batch_dml(string $instanceId, string $databaseId): void
{
$spanner = new SpannerClient();
$instance = $spanner->instance($instanceId);
$database = $instance->database($databaseId);
$batchDmlResult = $database->runTransaction(function (Transaction $t) {
$result = $t->executeUpdateBatch([
[
'sql' => 'INSERT INTO Albums '
. '(SingerId, AlbumId, AlbumTitle, MarketingBudget) '
. "VALUES (1, 3, 'Test Album Title', 10000)"
],
[
'sql' => 'UPDATE Albums '
. 'SET MarketingBudget = MarketingBudget * 2 '
. 'WHERE SingerId = 1 and AlbumId = 3'
],
]);
$t->commit();
$rowCounts = count($result->rowCounts());
printf('Executed %s SQL statements using Batch DML.' . PHP_EOL,
$rowCounts);
});
}Python
Use transaction.batch_update() to execute multiple DML statement strings.
fromgoogle.rpc.code_pb2import OK
# 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)
insert_statement = (
"INSERT INTO Albums "
"(SingerId, AlbumId, AlbumTitle, MarketingBudget) "
"VALUES (1, 3, 'Test Album Title', 10000)"
)
update_statement = (
"UPDATE Albums "
"SET MarketingBudget = MarketingBudget * 2 "
"WHERE SingerId = 1 and AlbumId = 3"
)
defupdate_albums(transaction):
status, row_cts = transaction.batch_update([insert_statement, update_statement])
if status.code != OK:
# Do handling here.
# Note: the exception will still be raised when
# `commit` is called by `run_in_transaction`.
return
print("Executed {} SQL statements using Batch DML.".format(len(row_cts)))
database.run_in_transaction(update_albums)Ruby
Use transaction.batch_update to execute multiple DML statement strings.
# 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.newproject:project_id
client=spanner.clientinstance_id,database_id
row_counts=nil
client.transactiondo|transaction|
row_counts=transaction.batch_updatedo|b|
b.batch_update(
"INSERT INTO Albums "\
"(SingerId, AlbumId, AlbumTitle, MarketingBudget) "\
"VALUES (1, 3, 'Test Album Title', 10000)"
)
b.batch_update(
"UPDATE Albums "\
"SET MarketingBudget = MarketingBudget * 2 "\
"WHERE SingerId = 1 and AlbumId = 3"
)
end
end
statement_count=row_counts.count
puts"Executed #{statement_count} SQL statements using Batch DML."