Simple SELECT Clause

The simple SELECT clause is the main SQL syntax to read and processexisting data.

When used as a stand-alone statement, the simple SELECT clause isalso called "the SELECT statement". However, it is also aselection clause that can be combinedwith other constructs to form more complex selection queries.

Synopsis

SELECTALLDISTINCTON(a_expr,)target_elem,FROMtable_ref,ASOFSYSTEMTIMEa_exprWHEREa_exprGROUPBYa_expr,HAVINGa_exprWINDOWwindow_definition_list

Tip:

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

ParameterDescription
DISTINCT or ALLSee Eliminate Duplicate Rows.
DISTINCT ON ( a_expr [, …] )DISTINCT ON followed by a list of scalar expressions within parentheses. See Eliminate Duplicate Rows.
target_elemA scalar expression to compute a column in each result row, or to automatically retrieve all columns from the FROM clause.If target_elem contains an aggregate function, a GROUP BY clause can be used to further control the aggregation.
table_refThe table expression 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 CROSS JOIN expression.
AS OF SYSTEM TIME timestampRetrieve data as it existed as of timestamp. *Note: Because AS OF SYSTEM TIME returns historical data, your reads might be stale.
WHERE a_exprOnly retrieve rows that return TRUE for a_expr, which must be a scalar expression that returns Boolean values using columns (e.g., <column> = <value>).
GROUP BY a_exprWhen using aggregate functions in target_elem or HAVING, list the column groupings after GROUP BY.
HAVING a_exprOnly retrieve aggregate function groups that return TRUE for a_expr, which must be a scalar expression that returns Boolean values using an aggregate function (e.g., <aggregate function> = <value>). HAVING works like the WHERE clause, but for aggregate functions.
WINDOW window_definition_listA list of window functions definitions.

Eliminate duplicate rows

The DISTINCT subclause specifies to remove duplicate rows.

By default, or when ALL is specified, SELECT returns all the rowsselected, without removing duplicates. When DISTINCT is specified,duplicate rows are eliminated.

Without ON, two rows are considered duplicates if they are equal onall the results computed by SELECT.

With ON, two rows are considered duplicates if they are equal onlyusing 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

Choose columns

Retrieve specific columns

Retrieve specific columns by naming them in a comma-separated list:

  1. > SELECT id, name, balance
  2. FROM accounts;
  1. +----+-----------------------+---------+
  2. | id | name | balance |
  3. +----+-----------------------+---------+
  4. | 1 | Bjorn Fairclough | 1200 |
  5. | 2 | Bjorn Fairclough | 2500 |
  6. | 3 | Arturo Nevin | 250 |
  7. [ truncated ]
  8. +----+-----------------------+---------+

Retrieve all columns

Retrieve all columns by using *:

  1. > SELECT *
  2. FROM accounts;
  1. +----+-----------------------+---------+----------+--------------+
  2. | id | name | balance | type | state_opened |
  3. +----+-----------------------+---------+----------+--------------+
  4. | 1 | Bjorn Fairclough | 1200 | checking | AL |
  5. | 2 | Bjorn Fairclough | 2500 | savings | AL |
  6. | 3 | Arturo Nevin | 250 | checking | AK |
  7. [ truncated ]
  8. +----+-----------------------+---------+----------+--------------+

Filter rows

Filter on a single condition

Filter rows with expressions that use columns and return Boolean values in the WHERE clause:

  1. > SELECT name, balance
  2. FROM accounts
  3. WHERE balance < 300;
  1. +------------------+---------+
  2. | name | balance |
  3. +------------------+---------+
  4. | Arturo Nevin | 250 |
  5. | Akbar Jinks | 250 |
  6. | Andrea Maas | 250 |
  7. +------------------+---------+

Filter on multiple conditions

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

  1. > SELECT *
  2. FROM accounts
  3. WHERE balance > 2500 AND NOT type = 'checking';
  1. +----+-------------------+---------+---------+--------------+
  2. | id | name | balance | type | state_opened |
  3. +----+-------------------+---------+---------+--------------+
  4. | 4 | Tullia Romijnders | 3000 | savings | AK |
  5. | 62 | Ruarc Mathews | 3000 | savings | OK |
  6. +----+-------------------+---------+---------+--------------+

Select distinct rows

Columns without the Primary Key or Unique constraints can have multiple instances of the same value:

  1. > SELECT name
  2. FROM accounts
  3. WHERE state_opened = 'VT';
  1. +----------------+
  2. | name |
  3. +----------------+
  4. | Sibylla Malone |
  5. | Sibylla Malone |
  6. +----------------+

Using DISTINCT, you can remove all but one instance of duplicate values from your retrieved data:

  1. > SELECT DISTINCT name
  2. FROM accounts
  3. WHERE state_opened = 'VT';
  1. +----------------+
  2. | name |
  3. +----------------+
  4. | Sibylla Malone |
  5. +----------------+

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:

  1. > SELECT name, balance, state_opened
  2. FROM accounts
  3. WHERE state_opened IN ('AZ', 'NY', 'WA');
  1. +-----------------+---------+--------------+
  2. | name | balance | state_opened |
  3. +-----------------+---------+--------------+
  4. | Naseem Joossens | 300 | AZ |
  5. | Aygün Sanna | 900 | NY |
  6. | Carola Dahl | 800 | NY |
  7. | Edna Barath | 750 | WA |
  8. | Edna Barath | 2200 | WA |
  9. +-----------------+---------+--------------+

Rename columns in output

Instead of outputting a column's name in the retrieved table, you can change its label using AS:

  1. > SELECT name AS NY_accounts, balance
  2. FROM accounts
  3. WHERE state_opened = 'NY';
  1. +-------------+---------+
  2. | NY_accounts | balance |
  3. +-------------+---------+
  4. | Aygün Sanna | 900 |
  5. | Carola Dahl | 800 |
  6. +-------------+---------+

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:
  1. > SELECT id, name, type
  2. FROM accounts
  3. WHERE name LIKE 'Anni%';
  1. +----+----------------+----------+
  2. | id | name | type |
  3. +----+----------------+----------+
  4. | 58 | Annibale Karga | checking |
  5. | 59 | Annibale Karga | savings |
  6. +----+----------------+----------+

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.

  1. > SELECT MIN(balance)
  2. FROM accounts;
  1. +--------------+
  2. | MIN(balance) |
  3. +--------------+
  4. | 250 |
  5. +--------------+

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:

  1. > SELECT id, name, balance
  2. FROM accounts
  3. WHERE balance = (
  4. SELECT
  5. MIN(balance)
  6. FROM accounts
  7. );
  1. +----+------------------+---------+
  2. | id | name | balance |
  3. +----+------------------+---------+
  4. | 3 | Arturo Nevin | 250 |
  5. | 10 | Henrik Brankovic | 250 |
  6. | 26 | Odalys Ziemniak | 250 |
  7. | 35 | Vayu Soun | 250 |
  8. +----+------------------+---------+

Perform aggregate function on retrieved rows

By filtering the statement, you can perform the calculation only on retrieved rows:

  1. > SELECT SUM(balance)
  2. FROM accounts
  3. WHERE state_opened IN ('AZ', 'NY', 'WA');
  1. +--------------+
  2. | SUM(balance) |
  3. +--------------+
  4. | 4950 |
  5. +--------------+

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:

  1. > SELECT count(*) AS unfiltered, count(*) FILTER (WHERE balance > 1500) AS filtered FROM accounts;
  1. +------------+----------+
  2. | unfiltered | filtered |
  3. +------------+----------+
  4. | 84 | 14 |
  5. +------------+----------+

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 used as a target_elem must be included in GROUP BY.

For example:

  1. > SELECT state_opened AS state, SUM(balance) AS state_balance
  2. FROM accounts
  3. WHERE state_opened IN ('AZ', 'NY', 'WA')
  4. GROUP BY state_opened;
  1. +-------+---------------+
  2. | state | state_balance |
  3. +-------+---------------+
  4. | AZ | 300 |
  5. | NY | 1700 |
  6. | WA | 2950 |
  7. +-------+---------------+

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:

  1. > SELECT state_opened, AVG(balance) as avg
  2. FROM accounts
  3. GROUP BY state_opened
  4. HAVING AVG(balance) BETWEEN 1700 AND 50000;
  1. +--------------+---------+
  2. | state_opened | avg |
  3. +--------------+---------+
  4. | AR | 3700.00 |
  5. | UT | 1750.00 |
  6. | OH | 2500.00 |
  7. | AL | 1850.00 |
  8. +--------------+---------+

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:

  1. > SELECT name, state_opened
  2. FROM accounts
  3. WHERE state_opened in ('LA', 'MO')
  4. GROUP BY name, state_opened
  5. HAVING COUNT(name) > 1;
  1. +----------------+--------------+
  2. | name | state_opened |
  3. +----------------+--------------+
  4. | Yehoshua Kleid | MO |
  5. +----------------+--------------+

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.

Note:

Index selection can impact performance, but does not change the result of a query.

The syntax to force a scan of a specific index is:

  1. > SELECT * FROM table@my_idx;

This is equivalent to the longer expression:

  1. > SELECT * FROM table@{FORCE_INDEX=my_idx};

New in v19.1: The syntax to force a reverse scan of a specific index is:

  1. > SELECT * FROM table@{FORCE_INDEX=my_idx,DESC};

Forcing a reverse can is sometimes useful during performance tuning. For reference, the full syntax for choosing an index and its scan direction is

  1. SELECT * FROM table@{FORCE_INDEX=idx[,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

  1. > CREATE TABLE kv (K INT PRIMARY KEY, v INT);

you can check the scan direction with:

  1. > EXPLAIN (opt) SELECT * FROM kv@{FORCE_INDEX=primary,DESC};

  1. text

scan kv,rev
└── flags: force-index=primary,rev
(2 rows)

To see all indexes available on a table, use SHOW INDEXES.

Select historical data (time-travel)

CockroachDB lets you find data as it was stored at a given point intime using AS OF SYSTEM TIME with various supportedformats. This can be also advantageous forperformance. For more details, see AS OF SYSTEM
TIME
.

Advanced uses of SELECT clauses

CockroachDB supports numerous ways to combine results from SELECTclauses together.

See Selection Queries fordetails. A few examples follow.

Sorting and limiting query results

To order the results of a SELECT clause or limit the number of rowsin the result, you can combine it with ORDER BY or LIMIT /OFFSET to form a selection query orsubquery.

See Ordering Query Results and Limiting QueryResults for more details.

Note:
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 NULL values 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 join expressions to combine rowsaccording to conditions on specific columns.
  • Using set operations to combine rowsusing inclusion/exclusion rules.

See also

Was this page helpful?
YesNo