Query statements scan one or more tables or expressions and return the computed result rows. This topic describes the syntax for SQL queries in GoogleSQL for Spanner.
SQL syntax notation rules
The following table lists and describes the syntax notation rules that GoogleSQL documentation commonly uses.
| Notation | Example | Description |
|---|---|---|
| Square brackets | [ ] |
Optional clauses |
| Parentheses | ( ) |
Literal parentheses |
| Vertical bar | | |
Logical XOR (exclusive OR) |
| Curly braces | { } |
A set of options, such as { a | b | c }. Select one option. |
| Ellipsis | ... |
The preceding item can repeat. |
| Comma | , |
Literal comma |
| Comma followed by an ellipsis | , ... |
The preceding item can repeat in a comma-separated list. |
| Item list | item [, ...] |
One or more items |
[item, ...] |
Zero or more items | |
| Double quotes | "" |
The enclosed syntax characters (for example, "{"..."}") are literal
and required. |
| Angle brackets | <> |
Literal angle brackets |
SQL syntax
query_statement: [ statement_hint_expr ] [ table_hint_expr ] [ group_hint_expr ] [ join_hint_expr ] query_expr query_expr: [ WITH cte[, ...] ] { select | ( query_expr ) | set_operation } [ ORDER BY expression [{ ASC | DESC }] [, ...] ] [ LIMIT count [ OFFSET skip_rows ] ] [ FOR UPDATE ] select: SELECT [ { ALL | DISTINCT } ] [ AS { typename | STRUCT | VALUE } ] select_list [ FROM from_clause[, ...] ] [ WHERE bool_expression ] [ GROUP [ group_hint_expr ] BY group_by_specification ] [ HAVING bool_expression ]
SELECT statement
SELECT
[ { ALL | DISTINCT } ]
[ AS { typename | STRUCT | VALUE } ]
select_list
select_list:
{ select_all | select_expression } [, ...]
select_all:
[ expression. ]*
[ EXCEPT ( column_name [, ...] ) ]
[ REPLACE ( expression AS column_name [, ...] ) ]
select_expression:
expression [ [ AS ] alias ]
The SELECT list defines the columns that the query will return. Expressions in
the SELECT list can refer to columns in any of the from_items in its
corresponding FROM clause.
Each item in the SELECT list is one of:
*expressionexpression.*
SELECT *
SELECT *, often referred to as select star, produces one output column for
each column that's visible after executing the full query.
SELECT * FROM (SELECT "apple" AS fruit, "carrot" AS vegetable);
/*-------+-----------+
| fruit | vegetable |
+-------+-----------+
| apple | carrot |
+-------+-----------*/
SELECT expression
Items in a SELECT list can be expressions. These expressions evaluate to a
single value and produce one output column, with an optional explicit alias.
If the expression doesn't have an explicit alias, it receives an implicit alias according to the rules for implicit aliases, if possible. Otherwise, the column is anonymous and you can't refer to it by name elsewhere in the query.
SELECT expression.*
An item in a SELECT list can also take the form of expression.*. This
produces one output column for each column or top-level field of expression.
The expression must either be a table alias or evaluate to a single value of a
data type with fields, such as a STRUCT.
The following query produces one output column for each column in the table
groceries, aliased as g.
WITH groceries AS
(SELECT "milk" AS dairy,
"eggs" AS protein,
"bread" AS grain)
SELECT g.*
FROM groceries AS g;
/*-------+---------+-------+
| dairy | protein | grain |
+-------+---------+-------+
| milk | eggs | bread |
+-------+---------+-------*/
More examples:
WITH locations AS
(SELECT STRUCT("Seattle" AS city, "Washington" AS state) AS location
UNION ALL
SELECT STRUCT("Phoenix" AS city, "Arizona" AS state) AS location)
SELECT l.location.*
FROM locations l;
/*---------+------------+
| city | state |
+---------+------------+
| Seattle | Washington |
| Phoenix | Arizona |
+---------+------------*/
WITH locations AS
(SELECT ARRAY<STRUCT<city STRING, state STRING>>[("Seattle", "Washington"),
("Phoenix", "Arizona")] AS location)
SELECT l.LOCATION[offset(0)].*
FROM locations l;
/*---------+------------+
| city | state |
+---------+------------+
| Seattle | Washington |
+---------+------------*/
SELECT * EXCEPT
A SELECT * EXCEPT statement specifies the names of one or more columns to
exclude from the result. All matching column names are omitted from the output.
WITH orders AS
(SELECT 5 as order_id,
"sprocket" as item_name,
200 as quantity)
SELECT * EXCEPT (order_id)
FROM orders;
/*-----------+----------+
| item_name | quantity |
+-----------+----------+
| sprocket | 200 |
+-----------+----------*/
SELECT * REPLACE
A SELECT * REPLACE statement specifies one or more
expression AS identifier clauses. Each identifier must match a column name
from the SELECT * statement. In the output column list, the column that
matches the identifier in a REPLACE clause is replaced by the expression in
that REPLACE clause.
A SELECT * REPLACE statement doesn't change the names or order of columns.
However, it can change the value and the value type.
WITH orders AS
(SELECT 5 as order_id,
"sprocket" as item_name,
200 as quantity)
SELECT * REPLACE ("widget" AS item_name)
FROM orders;
/*----------+-----------+----------+
| order_id | item_name | quantity |
+----------+-----------+----------+
| 5 | widget | 200 |
+----------+-----------+----------*/
WITH orders AS
(SELECT 5 as order_id,
"sprocket" as item_name,
200 as quantity)
SELECT * REPLACE (quantity/2 AS quantity)
FROM orders;
/*----------+-----------+----------+
| order_id | item_name | quantity |
+----------+-----------+----------+
| 5 | sprocket | 100 |
+----------+-----------+----------*/
SELECT DISTINCT
A SELECT DISTINCT statement discards duplicate rows and returns only the
remaining rows. SELECT DISTINCT can't return columns of the following types:
PROTOSTRUCTARRAYGRAPH_ELEMENTGRAPH_PATH
SELECT ALL
A SELECT ALL statement returns all rows, including duplicate rows.
SELECT ALL is the default behavior of SELECT.
Using STRUCTs with SELECT
Queries that return a
STRUCTat the root of the return type aren't supported in Spanner APIs. For example, the following query is supported only as a subquery:SELECT STRUCT(1, 2) FROM Users;Returning an array of structs is supported. For example, the following queries are supported in Spanner APIs:
SELECT ARRAY(SELECT STRUCT(1 AS A, 2 AS B)) FROM Users;SELECT ARRAY(SELECT AS STRUCT 1 AS a, 2 AS b) FROM Users;However, query shapes that can return an
ARRAY<STRUCT<...>>typedNULLvalue or anARRAY<STRUCT<...>>typed value with an element that'sNULLaren't supported in Spanner APIs, so the following query is supported only as a subquery:SELECT ARRAY(SELECT IF(STARTS_WITH(Users.username, "a"), NULL, STRUCT(1, 2))) FROM Users;
See Querying STRUCT elements in an ARRAY for more examples on
how to query STRUCTs inside an ARRAY.
Also see notes about using STRUCTs in subqueries.
SELECT AS STRUCT
SELECT AS STRUCT expr [[AS] struct_field_name1] [,...]
This produces a value table with a
STRUCT row type, where the
STRUCT field names and types match the column names
and types produced in the SELECT list.
Example:
SELECT ARRAY(SELECT AS STRUCT 1 a, 2 b)
SELECT AS STRUCT can be used in a scalar or array subquery to produce a single
STRUCT type grouping multiple values together. Scalar
and array subqueries (see Subqueries) are normally not
allowed to return multiple columns, but can return a single column with
STRUCT type.
Anonymous columns are allowed.
Example:
SELECT AS STRUCT 1 x, 2, 3
The query above produces STRUCT values of type
STRUCT<int64 x, int64, int64>. The first field has the name x while the
second and third fields are anonymous.
The example above produces the same result as this SELECT AS VALUE query using
a struct constructor:
SELECT AS VALUE STRUCT(1 AS x, 2, 3)
Duplicate columns are allowed.
Example:
SELECT AS STRUCT 1 x, 2 y, 3 x
The query above produces STRUCT values of type
STRUCT<int64 x, int64 y, int64 x>. The first and third fields have the same
name x while the second field has the name y.
The example above produces the same result as this SELECT AS VALUE query
using a struct constructor:
SELECT AS VALUE STRUCT(1 AS x, 2 AS y, 3 AS x)
SELECT AS typename
SELECT AS typename
expr [[AS] field]
[, ...]
A SELECT AS typename statement produces a value table where the row type
is a specific named type. Currently, protocol buffers are the
only supported type that can be used with this syntax.
When selecting as a type that has fields, such as a proto message type,
the SELECT list may produce multiple columns. Each produced column must have
an explicit or implicit alias that matches a unique field of
the named type.
When used with SELECT DISTINCT, or GROUP BY or ORDER BY using column
ordinals, these operators are first applied on the columns in the SELECT list.
The value construction happens last. This means that DISTINCT can be applied
on the input columns to the value construction, including in
cases where DISTINCT wouldn't be allowed after value construction because
grouping isn't supported on the constructed type.
The following is an example of a SELECT AS typename query.
SELECT AS tests.TestProtocolBuffer mytable.key int64_val, mytable.name string_val
FROM mytable;
The query returns the output as a tests.TestProtocolBuffer protocol
buffer. mytable.key int64_val means that values from the key column are
stored in the int64_val field in the protocol buffer. Similarly, values from
the mytable.name column are stored in the string_val protocol buffer field.
To learn more about protocol buffers, see Work with protocol buffers.
SELECT AS VALUE
SELECT AS VALUE produces a value table from any
SELECT list that produces exactly one column. Instead of producing an
output table with one column, possibly with a name, the output will be a
value table where the row type is just the value type that was produced in the
one SELECT column. Any alias the column had will be discarded in the
value table.
Example:
SELECT AS VALUE 1
The query above produces a table with row type INT64.
Example:
SELECT AS VALUE STRUCT(1 AS a, 2 AS b) xyz
The query above produces a table with row type STRUCT<a int64, b int64>.
Example:
SELECT AS VALUE v FROM (SELECT AS STRUCT 1 a, true b) v WHERE v.b
Given a value table v as input, the query above filters out certain values in
the WHERE clause, and then produces a value table using the exact same value
that was in the input table. If the query above didn't use SELECT AS VALUE,
then the output table schema would differ from the input table schema because
the output table would be a regular table with a column named v containing the
input value.
FROM clause
FROM from_clause[, ...] from_clause: from_item [ tablesample_operator ] from_item: { table_name [ table_hint_expr ] [ as_alias ] | { join_operation | ( join_operation ) } | ( query_expr ) [ table_hint_expr ] [ as_alias ] | field_path | unnest_operator | cte_name [ table_hint_expr ] [ as_alias ] | graph_table_operator [ as_alias ] } as_alias: [ AS ] alias
The FROM clause indicates the table or tables from which to retrieve rows,
and specifies how to join those rows together to produce a single stream of
rows for processing in the rest of the query.
tablesample_operator
See TABLESAMPLE operator.
graph_table_operator
See GRAPH_TABLE operator.
table_name
The name of an existing table.
SELECT * FROM Roster;
join_operation
See Join operation.
query_expr
( query_expr ) [ [ AS ] alias ] is a table subquery.
field_path
In the FROM clause, field_path is any path that
resolves to a field within a data type. field_path can go
arbitrarily deep into a nested data structure.
Some examples of valid field_path values include:
SELECT * FROM T1 t1, t1.array_column;
SELECT * FROM T1 t1, t1.struct_column.array_field;
SELECT (SELECT ARRAY_AGG(c) FROM t1.array_column c) FROM T1 t1;
SELECT a.struct_field1 FROM T1 t1, t1.array_of_structs a;
SELECT (SELECT STRING_AGG(a.struct_field1) FROM t1.array_of_structs a) FROM T1 t1;
Field paths in the FROM clause must end in an
array or a repeated field. In
addition, field paths can't contain arrays
or repeated fields before the end of the path. For example, the path
array_column.some_array.some_array_field is invalid because it
contains an array before the end of the path.
unnest_operator
See UNNEST operator.
cte_name
Common table expressions (CTEs) in a WITH Clause act like
temporary tables that you can reference anywhere in the FROM clause.
In the example below, subQ1 and subQ2 are CTEs.
Example:
WITH
subQ1 AS (SELECT * FROM Roster WHERE SchoolID = 52),
subQ2 AS (SELECT SchoolID FROM subQ1)
SELECT DISTINCT * FROM subQ2;
UNNEST operator
unnest_operator: { UNNEST( array ) [ as_alias ] | array_path [ as_alias ] } [ table_hint_expr ] [ WITH OFFSET [ as_alias ] ] array: { array_expression | array_path } as_alias: [AS] alias
The UNNEST operator takes an array and returns a table with one row for each
element in the array. The output of UNNEST is one value table column.
For these ARRAY element types, SELECT * against the value table column
returns multiple columns:
STRUCTPROTO
Input values:
array_expression: An expression that produces an array and that's not an array path.array_path: The path to anARRAYtype.- In an implicit
UNNESToperation, the path must start with a range variable name. - In an explicit
UNNESToperation, the path can optionally start with a range variable name.
The
UNNESToperation with any correlatedarray_pathmust be on the right side of aCROSS JOIN,LEFT JOIN, orINNER JOINoperation.- In an implicit
as_alias: If specified, defines the explicit name of the value table column containing the array element values. It can be used to refer to the column elsewhere in the query.WITH OFFSET:UNNESTdestroys the order of elements in the input array. Use this optional clause to return an additional column with the array element indexes, or offsets. Offset counting starts at zero for each row produced by theUNNESToperation. This column has an optional alias; If the optional alias isn't used, the default column name isoffset.Example:
SELECT * FROM UNNEST ([10,20,30]) as numbers WITH OFFSET; /*---------+--------+ | numbers | offset | +---------+--------+ | 10 | 0 | | 20 | 1 | | 30 | 2 | +---------+--------*/
You can also use UNNEST outside of the FROM clause with the
IN operator.
For several ways to use UNNEST, including construction, flattening, and
filtering, see Work with arrays.
To learn more about the ways you can use UNNEST explicitly and implicitly,
see Explicit and implicit UNNEST.
UNNEST and structs
For an input array of structs, UNNEST
returns a row for each struct, with a separate column for each field in the
struct. The alias for each column is the name of the corresponding struct
field.
Example:
SELECT *
FROM UNNEST(
ARRAY<
STRUCT<
x INT64,
y STRING,
z ARRAY<INT64>>>[
(1, 'foo', [10, 11]),
(3, 'bar', [20, 21])]);
/*---+-----+----------+
| x | y | z |
+---+-----+----------+
| 1 | foo | {10, 11} |
| 3 | bar | {20, 21} |
+---+-----+----------*/
UNNEST and protocol buffers
For an input array of protocol buffers, UNNEST returns a row for each
protocol buffer, with a separate column for each field in the
protocol buffer. The alias for each column is the name of the corresponding
protocol buffer field.
Example:
SELECT *
FROM UNNEST(
ARRAY<googlesql.examples.music.Album>[
NEW googlesql.examples.music.Album (
'The Goldberg Variations' AS album_name,
['Aria', 'Variation 1', 'Variation 2'] AS song
)
]
);
/*-------------------------+--------+----------------------------------+
| album_name | singer | song |
+-------------------------+--------+----------------------------------+
| The Goldberg Variations | NULL | [Aria, Variation 1, Variation 2] |
+-------------------------+--------+----------------------------------*/
As with structs, you can alias UNNEST to define a range variable. You
can reference this alias in the SELECT list to return a value table where each
row is a protocol buffer element from the array.
SELECT proto_value
FROM UNNEST(
ARRAY<googlesql.examples.music.Album>[
NEW googlesql.examples.music.Album (
'The Goldberg Variations' AS album_name,
['Aria', 'Var. 1'