SELECT clause is the main SQL syntax to read and process existing data.
When used as a stand-alone statement, the simple SELECT clause is also called “the SELECT statement”. However, it is also a that can be combined with other constructs to form more complex .
Synopsis
Required privileges
The user must have theSELECT on the tables used as operands.
Parameters
| Parameter | Description |
|---|---|
DISTINCT or ALL | See Eliminate Duplicate Rows. |
DISTINCT ON ( a\_expr [, ...] ) | DISTINCT ON followed by a list of within parentheses. See Eliminate Duplicate Rows. |
target\_elem | A to compute a column in each result row. \* automatically retrieves all columns. If a column has the , it is not returned with \*. If target\_elem contains an , a GROUP BY clause can be used to further control the aggregation. |
table\_ref | The you want to retrieve data from. Using two or more table expressions in the FROM sub-clause, separated with a comma, is equivalent to a expression. |
AS OF SYSTEM TIME timestamp | Retrieve data as it existed . Note: Because AS OF SYSTEM TIME returns historical data, your reads might be stale. |
WHERE a\_expr | Only retrieve rows that return TRUE for a\_expr, which must be a that returns Boolean values using columns (e.g., =). |
GROUP BY a\_expr | Group results on one or more columns. When an follows SELECT as a target\_elem, or HAVING as an a\_expr, you can create aggregate groups on column groupings listed after GROUP BY. You can group columns by an alias (i.e., a label assigned to the column with an AS clause) rather than the column name. If aggregate groups are created on a full primary key, any column in the table can be selected as a target\_elem, or specified in a HAVING clause. If a selected column is in a , and the column references a higher scope, the column does not need to be included in the GROUP BY clause (if one exists). Using a GROUP BY clause in a statement without an aggregate function is equivalent to using a DISTINCT ON clause on the grouping columns. |
HAVING a\_expr | Only retrieve aggregate function groups that return TRUE for a\_expr, which must be a that returns Boolean values using an aggregate function (e.g., =). HAVING works like the WHERE clause, but for aggregate functions. |
WINDOW window\_definition\_list | A list of . |
Eliminate duplicate rows
TheDISTINCT subclause specifies to remove duplicate rows.
By default, or when ALL is specified, SELECT returns all the rows selected, without removing duplicates. When DISTINCT is specified, duplicate rows are eliminated.
Without ON, two rows are considered duplicates if they are equal on all the results computed by SELECT.
With ON, two rows are considered duplicates if they are equal only using the listed with ON. When two rows are considered duplicates according to DISTINCT ON, the values from the first FROM row in the order specified by are used to compute the remaining target expressions. If ORDER BY is not specified, CockroachDB will pick any one of the duplicate rows as first row, non-deterministically.
Examples
Setup
To follow along, run to start a temporary, in-memory cluster with the sample dataset preloaded:Choose columns
Retrieve specific columns
Retrieve specific columns by naming them in a comma-separated list:Retrieve all columns
Retrieve all columns by using*:
Filter rows
Filter on a single condition
Filter rows with expressions that use columns and return Boolean values in theWHERE clause:
Filter on multiple conditions
To use multipleWHERE filters join them with AND or OR. You can also create negative filters with NOT:
Filter values with a list
UsingWHERE <column> IN (<comma separated list of values) performs an OR search for listed values in the specified column:
Select distinct rows
Columns without the or constraints can have multiple instances of the same value:DISTINCT, you can remove all but one instance of duplicate values from your retrieved data:
Rename columns in output
Instead of outputting a column’s name in the retrieved table, you can change its label usingAS:
Search for string values
Search for partial matches in columns usingLIKE, which supports the following wildcard operators:
%matches 0 or more characters._matches exactly 1 character.
Aggregate functions
perform calculations on retrieved rows.Perform aggregate function on entire column
By using an aggregate function as atarget_elem, you can perform the calculation on the entire column.
WHERE clause to select additional rows that were not part of the aggregate function itself:
Perform aggregate function on retrieved rows
By filtering the statement, you can perform the calculation only on retrieved rows:Filter columns fed into aggregate functions
You can useFILTER (WHERE <Boolean expression>) in the target_elem to filter which rows are processed by an aggregate function; those that return FALSE or NULL for the FILTER clause’s Boolean expression are not fed into the aggregate function:
Create aggregate groups
Instead of performing aggregate functions on an the entire set of retrieved rows, you can split the rows into groups and then perform the aggregate function on each of them. When creating aggregate groups, each column selected as atarget_elem must be included in a GROUP BY clause.
For example:
If the group is created on a primary key column, any column in the table can be selected as a
target_elem. If a selected column is in a that references a higher scope, a GROUP BY clause is not needed.Filter aggregate groups
To filter aggregate groups, useHAVING, which is the equivalent of the WHERE clause for aggregate groups, which must evaluate to a Boolean value.
For example:
Use aggregate functions in having clause
Aggregate functions can also be used in theHAVING clause without needing to be included as a target_elem.
For example:
Order aggregate function input rows by column
Non-commutative aggregate functions are sensitive to the order in which the rows are processed in the surroundingSELECT clause. To specify the order in which input rows are processed, you can add an clause within the function argument list.
For example, suppose you want to create an array of name values, ordered alphabetically, and grouped by city. You can use the following statement to do so:
revenue values from high-revenue rides, ordered by ride end_time:
SELECT clause, you can order the input rows of the multiple functions on different columns. For example:
Group by an alias
If a query includes an alias (i.e., a label assigned to the column with anAS clause), you can group the aggregations in the query by the alias rather than by the column name. For example:
Select from a specific index
By using the explicit index annotation, you can override CockroachDB’s index selection and use a specific when reading from a named table.Index selection can impact , but does not change the result of a query.
Force index scan
The syntax to force a scan of a specific index is:Force reverse scan
The syntax to force a reverse scan of a specific index is:DIRECTION is either ASC (ascending) or DESC (descending).
When a direction is specified, that scan direction is forced; otherwise the is free to choose the direction it calculates will result in the best performance.
You can verify that the optimizer is choosing your desired scan direction using . For example, given the table
Force partial index scan
To force a , your statement must have aWHERE clause that implies the partial index filter.
Force partial GIN index scan
To force a scan, your statement must have aWHERE clause that:
- Implies the partial index.
- Constrains the GIN index scan.
Prevent full scan
-
To prevent the optimizer from planning a full scan for a specific table, specify the
NO_FULL_SCANindex hint. For example: -
To prevent a full scan of a for a specific table, you must specify
NO_FULL_SCANin combination with the index name using . For example:This forces a constrained scan of the partial index. If a constrained scan of the partial index is not possible, an error is returned.
Select historical data (time-travel)
CockroachDB lets you find data as it was stored at a given point in time usingAS OF SYSTEM TIME with various . This can be also advantageous for performance. For more details, see .
Advanced uses of SELECT clauses
CockroachDB supports numerous ways to combine results from SELECT clauses together.
See for details. A few examples follow.
Sorting and limiting query results
To order the results of aSELECT clause or limit the number of rows in the result, you can combine it with ORDER BY or LIMIT / OFFSET to form a or .
See and for more details.
When
ORDER BY is not included in a query, rows are not sorted by any consistent criteria. Instead, CockroachDB returns them as the coordinating node receives them. Also, CockroachDB sorts first with ASC and last with DESC. This differs from PostgreSQL, which sorts NULL values last with ASC and first with DESC.Combining results from multiple queries
Results from two or more queries can be combined together as follows:- Using to combine rows according to conditions on specific columns.
- Using to combine rows using inclusion/exclusion rules.
Row-level locking for concurrency control with SELECT FOR UPDATE
SELECT... FOR UPDATE exclusively locks the rows returned by a , such that other transactions trying to access those rows must wait for the transaction that locked the rows to commit or rollback.
SELECT... FOR UPDATE can be used to:
-
Strengthen the isolation of a transaction. If you need to read and later update a row within a transaction, use
SELECT... FOR UPDATEto acquire an exclusive lock on the row. This guarantees data integrity between the transaction’s read and write operations. For details, see . -
Order transactions by controlling concurrent access to one or more rows of a table. These other transactions are placed into a queue based on when they tried to read the values of the locked rows.
Because this queueing happens during the read operation, the thrashing that would otherwise occur if multiple concurrently executing transactions attempt to
SELECTthe same data and thenUPDATEthe results of that selection is prevented. By preventing thrashing,SELECT... FOR UPDATEalso prevents that would otherwise occur due to . As a result, usingSELECT... FOR UPDATEleads to increased throughput and decreased tail latency for contended operations.
SELECT... FOR UPDATE does not completely eliminate the chance of . These errors can also arise due to . To eliminate the need for application-level retry logic, in addition to SELECT FOR UPDATE your application also needs to use a .
By default, CockroachDB uses the SELECT... FOR UPDATE locking mechanism during the initial row scan performed in and statement execution. To turn off implicit SELECT... FOR UPDATE locking for UPDATE and UPSERT statements, set the enable_implicit_select_for_update to false.
For an example, see .

