SQL reference
This page documents the R2 SQL syntax based on the currently supported grammar in public beta.
SELECT column_list | aggregation_function | approximate_functionFROM table_nameWHERE conditions --optional[GROUP BY column_list][HAVING conditions][ORDER BY column_name [DESC | ASC]][LIMIT number]R2 SQL supports metadata queries to explore available namespaces and tables.
Lists all available namespaces.
SHOW DATABASES;Alias for SHOW DATABASES. Lists all available namespaces.
SHOW NAMESPACES;Lists all tables within a specific namespace.
SHOW TABLES IN namespace_name;Describes the structure of a table, showing column names and data types.
DESCRIBE namespace_name.table_name;SELECT column_specification [, column_specification, ...]- Column name:
column_name - All columns:
*
SELECT * FROM namespace_name.table_nameSELECT user_id FROM namespace_name.table_nameSELECT user_id, timestamp, status FROM namespace_name.table_nameSELECT timestamp, user_id, response_code FROM namespace_name.table_nameSELECT aggregation_function(column_name)FROM table_nameGROUP BY column_list- COUNT(*): Counts total rows note: only
*is supported - SUM(column): Sums numeric values
- AVG(column): Calculates average of numeric values
- MIN(column): Finds minimum value
- MAX(column): Finds maximum value
-- Count rows by departmentSELECT department, COUNT(*)FROM my_namespace.sales_dataGROUP BY department
-- Sum decimal valuesSELECT region, SUM(total_amount)FROM my_namespace.sales_dataGROUP BY region
-- Average by categorySELECT category, AVG(price)FROM my_namespace.productsGROUP BY category
-- Min and MaxSELECT department, MIN(salary), MAX(salary)FROM my_namespace.employeesGROUP BY department
-- Invalid: No aliasesSELECT department, COUNT(*) AS total FROM my_namespace.sales_data GROUP BY department
-- Invalid: COUNT column nameSELECT COUNT(department) FROM my_namespace.sales_dataApproximate aggregation functions produce statistically estimated results while using significantly less memory and compute than their exact counterparts. On large datasets, approximate functions can return results orders of magnitude faster than equivalent exact aggregations such as COUNT(DISTINCT ...), typically with an average relative error of only a few percent.
Use approximate functions when you are analyzing large datasets and an approximate result is acceptable — for example, understanding traffic distributions, identifying top values, or estimating cardinality across high-volume tables. Use exact aggregation functions when precise results are required, such as for billing or compliance reporting.
SELECT approximate_function(column_name [, ...])FROM table_name[WHERE conditions][GROUP BY column_list]- APPROX_PERCENTILE_CONT(column, percentile): Uses a t-digests algorithm to return the approximate value at the given percentile. The
percentileparameter must be between0.0and1.0inclusive. Works on integer and decimal columns. - APPROX_PERCENTILE_CONT_WITH_WEIGHT(column, weight, percentile): Uses a t-digests algorithm to return the approximate percentile weighted by the
weightcolumn. Thepercentileparameter must be between0.0and1.0inclusive. Works on integer and decimal columns. - APPROX_MEDIAN(column): Uses a t-digests algorithm to return the approximate median value. Equivalent to
APPROX_PERCENTILE_CONT(column, 0.5). Works on integer and decimal columns. - APPROX_DISTINCT(column): Uses HyperLogLog to return the approximate number of distinct values in a column. Works on any column type.
- APPROX_TOP_K(column, k): Uses a filtered space-saving algorithm to return the
kmost frequent values in a column along with their approximate counts. Thekparameter must be a positive integer. Returns a JSON array of\{"value", "count"\}objects. Works on string columns.
-- Approximate percentiles on a numeric columnSELECT approx_percentile_cont(total_amount, 0.25), approx_percentile_cont(total_amount, 0.5), approx_percentile_cont(total_amount, 0.75)FROM my_namespace.sales_data
-- Percentile with GROUP BYSELECT department, approx_percentile_cont(total_amount, 0.5)FROM my_namespace.sales_dataGROUP BY department
-- Weighted percentile (rows weighted by quantity)SELECT approx_percentile_cont_with_weight(unit_price, quantity, 0.5)FROM my_namespace.sales_data
-- Approximate medianSELECT department, approx_median(total_amount)FROM my_namespace.sales_dataGROUP BY department
-- Approximate distinct countSELECT approx_distinct(customer_id)FROM my_namespace.sales_data
-- Multiple distinct counts in one querySELECT approx_distinct(department), approx_distinct(region), approx_distinct(customer_id)FROM my_namespace.sales_data
-- Top-k most frequent valuesSELECT approx_top_k(department, 3)FROM my_namespace.sales_data
-- Combine approximate and standard aggregationsSELECT COUNT(*), SUM(total_amount), AVG(total_amount), approx_percentile_cont(total_amount, 0.5)FROM my_namespace.sales_data
-- With WHERE filterSELECT approx_median(total_amount), approx_distinct(customer_id)FROM my_namespace.sales_dataWHERE region = 'North'
-- Invalid: percentile out of rangeSELECT approx_percentile_cont(total_amount, 1.5) FROM my_namespace.sales_data
-- Invalid: k must be positiveSELECT approx_top_k(department, 0) FROM my_namespace.sales_dataSELECT * FROM table_nameSELECT * WHERE condition [AND|OR condition ...]column_name IS NULLcolumn_name IS NOT NULL
column_name BETWEEN value' AND 'valuecolumn_name = valuecolumn_name >= valuecolumn_name > valuecolumn_name <= valuecolumn_name < valuecolumn_name != valuecolumn_name LIKE 'value%'
AND- Logical ANDOR- Logical OR
- integer - Whole numbers
- float - Decimal numbers
- string - Text values (quoted)
- timestamp - RFC3339 format (
'YYYY-DD-MMT-HH:MM:SSZ') - date - Date32/Data64 expressed as a string (
'YYYY-MM-DD') - boolean - Explicitly valued (true, false)
SELECT * FROM namespace_name.table_name WHERE timestamp BETWEEN '2025-09-24T01:00:00Z' AND '2025-09-25T01:00:00Z'SELECT * FROM namespace_name.table_name WHERE status = 200SELECT * FROM namespace_name.table_name WHERE response_time > 1000SELECT * FROM namespace_name.table_name WHERE user_id IS NOT NULLSELECT * FROM namespace_name.table_name WHERE method = 'GET' AND status >= 200 AND status < 300SELECT * FROM namespace_name.table_name WHERE (status = 404 OR status = 500) AND timestamp > '2024-01-01'SELECT column_list, aggregation_functionFROM table_name[WHERE conditions]GROUP BY column_list-- Single column groupingSELECT department, COUNT(*)FROM my_namespace.sales_dataGROUP BY department
-- Multiple column groupingSELECT department, category, COUNT(*)FROM my_namespace.sales_dataGROUP BY department, category
-- With WHERE filterSELECT region, COUNT(*)FROM my_namespace.sales_dataWHERE status = 'completed'GROUP BY region
-- With ORDER BY (COUNT only)SELECT region, COUNT(*)FROM my_namespace.sales_dataGROUP BY regionORDER BY COUNT(*) DESCLIMIT 10
-- ORDER BY SUMSELECT department, SUM(amount)FROM my_namespace.sales_dataGROUP BY departmentORDER BY SUM(amount) DESCSELECT column_list, COUNT(*)FROM table_nameGROUP BY column_listHAVING SUM/COUNT/MIN/MAX/AVG(column_name) comparison_operator value-- Filter by count thresholdSELECT department, COUNT(*)FROM my_namespace.sales_dataGROUP BY departmentHAVING COUNT(*) > 1000
-- Multiple conditionsSELECT region, COUNT(*)FROM my_namespace.sales_dataGROUP BY regionHAVING COUNT(*) >= 100
-- HAVING with SUMSELECT department, SUM(amount)FROM my_namespace.sales_dataGROUP BY departmentHAVING SUM(amount) > 1000000--Note: ORDER BY only supports ordering by the partition keyORDER BY partition_key [DESC]- ASC: Ascending order
- DESC: Descending order
- Default: DESC on all columns of the partition key
- Can contain any columns from the partition key
SELECT * FROM namespace_name.table_name WHERE ... ORDER BY partition_key_ASELECT * FROM namespace_name.table_name WHERE ... ORDER BY partition_key_B DESCSELECT * FROM namespace_name.table_name WHERE ... ORDER BY partition_key_A ASCLIMIT number- Range: 1 to 10,000
- Type: Integer only
- Default: 500
SELECT * FROM namespace_name.table_name WHERE ... LIMIT 100SELECT *FROM my_namespace.http_requestsWHERE timestamp BETWEEN '2025-09-24T01:00:00Z' AND '2025-09-25T01:00:00Z'LIMIT 100SELECT user_id, timestamp, status, response_timeFROM my_namespace.access_logsWHERE status >= 400 AND response_time > 5000ORDER BY response_time DESCLIMIT 50SELECT timestamp, method, status, user_agentFROM my_namespace.http_requestsWHERE (method = 'POST' OR method = 'PUT') AND status BETWEEN 200 AND 299 AND user_agent IS NOT NULLORDER BY timestamp DESCLIMIT 1000SELECT user_id, session_id, date_columnFROM my_namespace.user_eventsWHERE session_id IS NOT NULL AND date_column >= '2024-01-01'ORDER BY timestampLIMIT 500SELECT department, COUNT(*)FROM my_namespace.sales_dataWHERE sale_date >= '2024-01-01'GROUP BY departmentORDER BY COUNT(*) DESCLIMIT 10SELECT region, COUNT(*)FROM my_namespace.sales_dataWHERE status = 'completed'GROUP BY regionHAVING COUNT(*) > 1000LIMIT 20SELECT department, category, MIN(price), MAX(price)FROM my_namespace.productsGROUP BY department, categoryLIMIT 100| Type | Description | Example Values |
|---|---|---|
integer | Whole numbers | 1, 42, -10, 0 |
float | Decimal numbers | 1.5, 3.14, -2.7, 0.0 |
string | Text values | 'hello', 'GET', '2024-01-01' |
boolean | Boolean values | true, false |
timestamp | RFC3339 | '2025-09-24T01:00:00Z' |
date | 'YYYY-MM-DD' | '2025-09-24' |
-- Integer comparisonsSELECT * FROM namespace_name.table_name WHERE status = 200SELECT * FROM namespace_name.table_name WHERE response_time > 1000
-- Float comparisonsSELECT * FROM namespace_name.table_name WHERE cpu_usage >= 85.5SELECT * FROM namespace_name.table_name WHERE memory_ratio < 0.8
-- String comparisonsSELECT * FROM namespace_name.table_name WHERE method = 'POST'SELECT * FROM namespace_name.table_name WHERE user_agent != 'bot'SELECT * FROM namespace_name.table_name WHERE country_code = 'US'- Comparison operators:
=,!=,<,<=,>,>=,LIKE,BETWEEN,IS NULL,IS NOT NULL - AND (higher precedence)
- OR (lower precedence)
Use parentheses to override default precedence:
SELECT * FROM namespace_name.table_name WHERE (status = 404 OR status = 500) AND method = 'GET'