Skip to main content
The simple 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 selection clause that can be combined with other constructs to form more complex selection queries.

Synopsis

simple_select_clause syntax diagram
The simple SELECT clause also has other applications not covered here, such as executing functions like SELECT current_timestamp();.

Required privileges

The user must have the SELECT privilege on the tables used as operands.

Parameters

Eliminate duplicate rows

The DISTINCT 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 scalar expressions 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 ORDER 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 cockroach demo to start a temporary, in-memory cluster with the movr 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 the WHERE clause:

Filter on multiple conditions

To use multiple WHERE filters join them with AND or OR. You can also create negative filters with NOT:

Filter values with a list

Using WHERE <column> IN (<comma separated list of values) performs an OR search for listed values in the specified column:

Select distinct rows

Columns without the Primary Key or Unique constraints can have multiple instances of the same value:
Using 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 using AS:
This does not change the name of the column in the table. To do that, use RENAME COLUMN.

Search for string values

Search for partial string matches in columns using LIKE, which supports the following wildcard operators:
  • % matches 0 or more characters.
  • _ matches exactly 1 character.
For example:

Aggregate functions

Aggregate functions perform calculations on retrieved rows.

Perform aggregate function on entire column

By using an aggregate function as a target_elem, you can perform the calculation on the entire column.
You can also use the retrieved value as part of an expression. For example, you can use the result in the 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 use FILTER (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 a target_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 subquery that references a higher scope, a GROUP BY clause is not needed.

Filter aggregate groups

To filter aggregate groups, use HAVING, 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 the HAVING 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 surrounding SELECT clause. To specify the order in which input rows are processed, you can add an ORDER BY 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:
You can also order input rows using a column different than the input row column. The following statement returns an array of revenue values from high-revenue rides, ordered by ride end_time:
If you include multiple aggregate functions in a single 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 an AS 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 index when reading from a named table.
Index selection can impact performance, but does not change the result of a query.
Force index scan
To force a scan of a specific index:
This is equivalent to the longer expression:
Force reverse scan
To force a reverse scan of a specific index:
Forcing a reverse scan can help with performance tuning. To choose an index and its scan direction:
where the optional DIRECTION is either ASC (ascending) or DESC (descending). When a direction is specified, that scan direction is forced; otherwise the cost-based optimizer 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 EXPLAIN (OPT). For example, given the table
you can check the scan direction with:

Force inverted index scan

To force a scan of any inverted index of the hinted table:
The FORCE_INVERTED_INDEX hint does not allow specifying an inverted index. If no query plan can be generated, the query will result in the error:
Force partial index scan
To force a partial index scan, your statement must have a WHERE clause that implies the partial index filter.
Force partial GIN index scan
To force a partial GIN index scan, your statement must have a WHERE 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_SCAN index hint. For example:
  • To prevent a full scan of a partial index for a specific table, you must specify NO_FULL_SCAN in combination with the index name using FORCE_INDEX. 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.
For other ways to prevent full scans, refer to Prevent the optimizer from planning full scans.

Select historical data (time-travel)

CockroachDB lets you find data as it was stored at a given point in time using AS OF SYSTEM TIME with various supported formats. This can be also advantageous for performance. For more details, see AS OF SYSTEM TIME.

Advanced uses of SELECT clauses

CockroachDB supports numerous ways to combine results from SELECT clauses together. See Selection Queries for details. A few examples follow.

Sorting and limiting query results

To order the results of a SELECT clause or limit the number of rows in the result, you can combine it with ORDER BY or LIMIT / OFFSET to form a selection query or subquery. See Ordering Query Results and Limiting Query Results for more details.

Combining results from multiple queries

Results from two or more queries can be combined together as follows:
  • Using JOIN expressions to combine rows according to conditions on specific columns.
  • Using set operations 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 selection query, 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 READ COMMITTED transaction. If you need to read and later update a row within a transaction, use SELECT ... FOR UPDATE to acquire an exclusive lock on the row. This guarantees data integrity between the transaction’s read and write operations. For details, see Locking reads.
  • Order SERIALIZABLE 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 SELECT the same data and then UPDATE the results of that selection is prevented. By preventing thrashing, SELECT ... FOR UPDATE also prevents transaction retries that would otherwise occur due to contention. As a result, using SELECT ... FOR UPDATE leads to increased throughput and decreased tail latency for contended operations.
Note that using SELECT ... FOR UPDATE does not completely eliminate the chance of serialization errors. These errors can also arise due to time uncertainty. To eliminate the need for application-level retry logic, in addition to SELECT FOR UPDATE your application also needs to use a driver that implements automatic retry handling.
By default, CockroachDB uses the SELECT ... FOR UPDATE locking mechanism during the initial row scan performed in UPDATE and UPSERT statement execution. To turn off implicit SELECT ... FOR UPDATE locking for UPDATE and UPSERT statements, set the enable_implicit_select_for_update session variable to false.
For an example, see FOR UPDATE and FOR SHARE.

See also