← R2 SQL / r2-sql
reference SQL
R2 SQL je bezserverový distribuovaný analytický dotazovací engine Cloudflare určený k dotazování Apache Iceberg ↗ tabulky uložené v R2 Data Catalog. Tato stránka popisuje podporovanou syntaxi SQL.
Syntaxe dotazu
SELECT [DISTINCT] column_list | expression | aggregate_function | window_function
FROM namespace_name.table_name
[JOIN namespace_name.table_name ON condition]
[WHERE conditions]
[GROUP BY column_list]
[HAVING conditions]
[QUALIFY window_condition]
[ORDER BY expression [ASC | DESC]]
[LIMIT number]Dva nebo více dotazů lze kombinovat pomocí množinové operace (UNION, UNION ALL, INTERSECT, EXCEPT).
Příkazy pro zjišťování schématu
SHOW DATABASES
Vypíše všechny dostupné jmenné prostory.
SHOW DATABASES;SHOW NAMESPACES
Alias pro SHOW DATABASES. Zobrazí seznam všech dostupných jmenných prostorů.
SHOW NAMESPACES;SHOW TABLES
Vypíše všechny tabulky v daném jmenném prostoru.
SHOW TABLES IN namespace_name;DESCRIBE
Popisuje strukturu tabulky, včetně názvů sloupců a datových typů.
DESCRIBE namespace_name.table_name;Klauzule SELECT
Syntaxe
SELECT [DISTINCT] column_specification [, column_specification, ...]Specifikace sloupce
- Název sloupce:
column_name - Všechny sloupce:
* - Kvalifikovaný zástupný znak:
table_name.* - Alias sloupce:
column_name AS alias - Výrazy: aritmetika, volání funkcí, výrazy CASE a přetypování
Příklady
SELECT * FROM my_namespace.sales_data LIMIT 10
SELECT customer_id, region, total_amount FROM my_namespace.sales_data LIMIT 10
SELECT region, total_amount * 1.1 AS total_with_tax FROM my_namespace.sales_data LIMIT 10DISTINCT
SELECT DISTINCT vrací unikátní řádky. DISTINCT ON (...) vrací první řádek pro každou kombinaci uvedených výrazů, a to pomocí ORDER BY klauzuli, která určuje, který řádek se zachová.
-- Unique combinations
SELECT DISTINCT region, department FROM my_namespace.sales_data
-- First row per region by amount
SELECT DISTINCT ON (region) region, customer_id, total_amount
FROM my_namespace.sales_data
ORDER BY region, total_amount DESCPro počítání jedinečných hodnot ve velkých datových sadách approx_distinct() je rychlejší alternativou.
Obecné tabulkové výrazy (CTE)
CTE umožňují definovat pojmenované dočasné sady výsledků pomocí WITH na které se můžete odkazovat v hlavním dotazu. CTE mohou odkazovat na různé tabulky a mohou obsahovat JOIN. CTE lze také spojit s jinými CTE nebo běžnými tabulkami v hlavním dotazu.
Syntaxe
WITH cte_name AS (
SELECT ...
FROM namespace_name.table_name
[WHERE ...]
)
SELECT ... FROM cte_nameZřetězené CTE
CTE může odkazovat na dříve definované CTE.
WITH filtered AS (
SELECT customer_id, department, total_amount
FROM my_namespace.sales_data
WHERE total_amount > 0
),
summary AS (
SELECT department,
COUNT(*) AS order_count,
round(AVG(total_amount), 2) AS avg_amount
FROM filtered
GROUP BY department
)
SELECT *
FROM summary
WHERE order_count > 100
ORDER BY avg_amount DESCCTE spojené s jinou tabulkou
WITH enterprise_zones AS (
SELECT zone_id, domain, plan
FROM my_namespace.zones
WHERE plan = 'enterprise'
)
SELECT ez.domain, f.action, COUNT(*) AS cnt
FROM enterprise_zones ez
INNER JOIN my_namespace.firewall_events f ON ez.zone_id = f.zone_id
GROUP BY ez.domain, f.action
ORDER BY cnt DESC
LIMIT 20Dvě CTE spojené pomocí joinu
WITH top_zones AS (
SELECT zone_id, COUNT(*) AS req_count
FROM my_namespace.http_requests
GROUP BY zone_id
ORDER BY req_count DESC
LIMIT 50
),
zone_threats AS (
SELECT zone_id, COUNT(*) AS threat_count
FROM my_namespace.firewall_events
WHERE risk_score > 0.5
GROUP BY zone_id
)
SELECT tz.zone_id, tz.req_count, COALESCE(zt.threat_count, 0) AS threat_count
FROM top_zones tz
LEFT JOIN zone_threats zt ON tz.zone_id = zt.zone_id
ORDER BY tz.req_count DESC
LIMIT 20Klauzule FROM
Syntaxe
SELECT * FROM namespace_name.table_nameDotazy R2 SQL mohou odkazovat na jednu nebo více tabulek. Tabulky se zadávají jako namespace_name.table_name. Více tabulek lze kombinovat pomocí JOIN nebo syntaxe oddělené čárkami. Více informací najdete v Klauzule JOIN část, kde najdete podrobnosti.
Klauzule JOIN
R2 SQL umožňuje spojovat více tabulek Iceberg v jednom dotazu. Všechny typy spojení používají standardní syntaxi SQL.
Podporované typy joinů
| Typ spojení | Syntaxe | Popis |
|---|---|---|
| Vnitřní spojení | INNER JOIN ... ON |
Vrátí řádky, které se shodují v obou tabulkách |
| Levé vnější spojení | LEFT JOIN ... ON |
Vrátí všechny řádky z levé tabulky, u nespárovaných řádků z pravé tabulky doplní NULL |
| Pravé vnější spojení | RIGHT JOIN ... ON |
Vrátí všechny řádky z pravé tabulky, u nespárovaných řádků z levé tabulky doplní NULL |
| Úplné vnější spojení | FULL OUTER JOIN ... ON |
Vrátí všechny řádky z obou tabulek, u nespárovaných řádků doplní NULL |
| Cross join | CROSS JOIN |
Kartézský součin obou tabulek |
| Implicitní spojení | FROM t1, t2 WHERE t1.id = t2.id |
Tabulky oddělené čárkami s podmínkou spojení v WHERE |
Syntaxe
-- Explicit JOIN
SELECT columns
FROM namespace.table1 alias1
[INNER | LEFT | RIGHT | FULL OUTER | CROSS] JOIN namespace.table2 alias2
ON alias1.column = alias2.column
[WHERE conditions]
-- Implicit join
SELECT columns
FROM namespace.table1 alias1, namespace.table2 alias2
WHERE alias1.column = alias2.columnVícenásobná spojení
V jednom dotazu můžete spojit tři a více tabulek:
SELECT z.domain, h.method, f.action, COUNT(*) AS cnt
FROM my_namespace.zones z
INNER JOIN my_namespace.http_requests h ON z.zone_id = h.zone_id
INNER JOIN my_namespace.firewall_events f ON z.zone_id = f.zone_id
WHERE h.status_code >= 400
GROUP BY z.domain, h.method, f.action
ORDER BY cnt DESC
LIMIT 20Self joiny
Tabulku lze spojit samu se sebou pomocí různých aliasů:
SELECT f1.source_ip, f1.zone_id AS zone1, f2.zone_id AS zone2
FROM my_namespace.firewall_events f1
INNER JOIN my_namespace.firewall_events f2
ON f1.source_ip = f2.source_ip
AND f1.zone_id < f2.zone_id
WHERE f1.action = 'block'
LIMIT 20Podmínky spojení
- Podmínky spojení používají klauzuli
ONklauzuli s podmínkou rovnosti (=) nebo predikáty založené na výrazech. - Funkce jsou podporovány v predikátech spojení (například
ON LOWER(a.col) = LOWER(b.col)). - Více podmínek lze kombinovat pomocí
AND.
Doporučené postupy pro spojení
- Vložte
WHEREfiltry, abyste zmenšili velikost mezivýsledků, zejména u vícenásobných joinů. - Velké faktové tabulky spojujte přes sdílenou dimenzní tabulku, ne přímým křížovým spojením dvou velkých tabulek.
- Použijte
LIMITk omezení velikosti výsledků.
Poddotazy
R2 SQL podporuje poddotazy na více místech v rámci dotazu.
Poddotazy ve FROM (odvozené tabulky)
Poddotaz v FROM vytváří odvozenou tabulku, na kterou lze odkazovat ve vnějším dotazu:
SELECT sub.domain, sub.total_requests
FROM (
SELECT z.domain, COUNT(*) AS total_requests
FROM my_namespace.zones z
INNER JOIN my_namespace.http_requests h ON z.zone_id = h.zone_id
GROUP BY z.domain
) sub
WHERE sub.total_requests > 1000
ORDER BY sub.total_requests DESC
LIMIT 20Odvozené tabulky lze spojovat s dalšími odvozenými tabulkami nebo běžnými tabulkami:
SELECT req.domain, req.total_reqs, fw.total_events
FROM (
SELECT zone_id, domain, COUNT(*) AS total_reqs
FROM my_namespace.zones z
INNER JOIN my_namespace.http_requests h ON z.zone_id = h.zone_id
GROUP BY zone_id, domain
) req
INNER JOIN (
SELECT zone_id, COUNT(*) AS total_events
FROM my_namespace.firewall_events
GROUP BY zone_id
) fw ON req.zone_id = fw.zone_id
ORDER BY fw.total_events DESC
LIMIT 20IN / NOT IN poddotazy
Filtrujte řádky podle toho, zda hodnota existuje ve výsledku poddotazu:
-- Find requests from enterprise zones
SELECT method, status_code, COUNT(*) AS cnt
FROM my_namespace.http_requests
WHERE zone_id IN (
SELECT zone_id FROM my_namespace.zones WHERE plan = 'enterprise'
)
GROUP BY method, status_code
ORDER BY cnt DESC
LIMIT 20-- NOT IN example
SELECT zone_id, COUNT(*) AS cnt
FROM my_namespace.http_requests
WHERE zone_id NOT IN (
SELECT zone_id FROM my_namespace.firewall_events WHERE action = 'block'
)
GROUP BY zone_id
LIMIT 10EXISTS / NOT EXISTS poddotazy
Test existence řádků odpovídajících korelované podmínce:
-- Find zones with blocked firewall events (semi-join)
SELECT z.domain, z.plan
FROM my_namespace.zones z
WHERE EXISTS (
SELECT 1 FROM my_namespace.firewall_events f
WHERE f.zone_id = z.zone_id AND f.action = 'block'
)
ORDER BY z.domain
LIMIT 20-- Find zones with NO firewall events (anti-join)
SELECT z.domain, z.plan
FROM my_namespace.zones z
WHERE NOT EXISTS (
SELECT 1 FROM my_namespace.firewall_events f
WHERE f.zone_id = z.zone_id
)
ORDER BY z.domain
LIMIT 20Skalární poddotazy
Poddotaz, který vrací jedinou hodnotu, lze použít v SELECT, WHERE, nebo HAVING:
-- In SELECT (constant value per row)
SELECT z.domain, z.plan,
(SELECT COUNT(*) FROM my_namespace.zones) AS total_zones
FROM my_namespace.zones z
WHERE z.plan = 'enterprise'
LIMIT 10-- In WHERE (comparison)
SELECT z.domain, z.plan, z.requests_30d
FROM my_namespace.zones z
WHERE z.requests_30d > (
SELECT AVG(requests_30d) FROM my_namespace.zones
)
ORDER BY z.requests_30d DESC
LIMIT 20Klauzule WHERE
Syntaxe
SELECT * FROM namespace_name.table_name WHERE condition [AND | OR condition ...]Podmínky
Porovnávací operátory
=, !=, <>, <, >, <=, >=
Kontrola hodnot NULL
column_name IS NULLcolumn_name IS NOT NULL
Booleovské kontroly
IS TRUE,IS FALSE,IS NOT TRUE,IS NOT FALSEIS UNKNOWN,IS NOT UNKNOWN
Rozsah
column_name BETWEEN value1 AND value2column_name NOT BETWEEN value1 AND value2
Členství v seznamu
column_name IN ('value1', 'value2')column_name NOT IN ('value1', 'value2')
Porovnávání vzorů
column_name LIKE 'pattern'column_name NOT LIKE 'pattern'column_name ILIKE 'pattern'(nerozlišuje velká a malá písmena)column_name NOT ILIKE 'pattern'column_name SIMILAR TO 'regex_pattern'
Logické operátory
ANDORNOT
Příklady
SELECT * FROM my_namespace.sales_data
WHERE timestamp BETWEEN '2025-09-24T01:00:00Z' AND '2025-09-25T01:00:00Z'
SELECT * FROM my_namespace.sales_data
WHERE status = 200 AND response_time > 1000
SELECT * FROM my_namespace.sales_data
WHERE (region = 'North' OR region = 'South')
AND total_amount IS NOT NULL
SELECT * FROM my_namespace.sales_data
WHERE department ILIKE '%eng%'Klauzule GROUP BY
Syntaxe
SELECT column_list, aggregation_function(column)
FROM namespace_name.table_name
[WHERE conditions]
GROUP BY column_listPříklady
SELECT department, COUNT(*) AS dept_count
FROM my_namespace.sales_data
GROUP BY department
SELECT department, category, SUM(total_amount) AS total
FROM my_namespace.sales_data
GROUP BY department, categoryGROUPING SETS, ROLLUP a CUBE
Tato rozšíření vypočítají více seskupení, včetně mezisoučtů a celkových součtů, v rámci jednoho dotazu.
GROUPING SETS: Vypočítá přesně ty seskupení, která uvedete.()vytváří celkový součet.ROLLUP: Počítá hierarchické mezisoučty zleva doprava.ROLLUP(a, b)seskupuje podle(a, b),(a), a().CUBE: Vypočítá každou kombinaci uvedených sloupců.CUBE(a, b)seskupuje podle(a, b),(a),(b), a().
-- Subtotals per department plus a grand total
SELECT department, SUM(total_amount) AS total
FROM my_namespace.sales_data
GROUP BY ROLLUP(department)
-- Every combination of department and category
SELECT department, category, SUM(total_amount) AS total
FROM my_namespace.sales_data
GROUP BY CUBE(department, category)
-- Explicit groupings
SELECT department, category, SUM(total_amount) AS total
FROM my_namespace.sales_data
GROUP BY GROUPING SETS ((department, category), (department), ())Klauzule HAVING
Syntaxe
SELECT column_list, aggregation_function(column) AS alias
FROM namespace_name.table_name
GROUP BY column_list
HAVING aggregation_function(column) comparison_operator valuePříklady
SELECT department, COUNT(*) AS dept_count
FROM my_namespace.sales_data
GROUP BY department
HAVING COUNT(*) > 1000
SELECT region, SUM(total_amount) AS total
FROM my_namespace.sales_data
GROUP BY region
HAVING SUM(total_amount) > 1000000Klauzule ORDER BY
Syntaxe
ORDER BY expression [ASC | DESC] [, expression [ASC | DESC], ...]- ASC: Vzestupné pořadí (výchozí)
- DESC: Sestupné pořadí
- Řazení podle více sloupců je podporováno
Příklady
SELECT customer_id, total_amount
FROM my_namespace.sales_data
WHERE total_amount IS NOT NULL
ORDER BY total_amount DESC
LIMIT 50
SELECT department, COUNT(*) AS dept_count
FROM my_namespace.sales_data
GROUP BY department
ORDER BY dept_count DESC, department ASCKlauzule LIMIT
Syntaxe
LIMIT number- Typ: Pouze celé číslo
- Výchozí: 500
Příklady
SELECT * FROM my_namespace.sales_data LIMIT 100Okenní funkce
Okenní funkce počítají hodnotu napříč sadou řádků souvisejících s aktuálním řádkem, aniž by je slučovaly do jediného výstupního řádku. Okno se definuje přímo pomocí OVER (...) klauzuli obsahující volitelnou PARTITION BY, ORDER BY, a specifikace rámce.
Syntaxe
function(args) OVER (
[PARTITION BY expression [, ...]]
[ORDER BY expression [ASC | DESC] [, ...]]
[frame_specification]
)Podporované funkce
| Kategorie | Funkce |
|---|---|
| Žebříček | ROW_NUMBER, RANK, DENSE_RANK, PERCENT_RANK, CUME_DIST, NTILE |
| Offset | LAG, LEAD, FIRST_VALUE, LAST_VALUE, NTH_VALUE |
| Agregace | SUM, AVG, COUNT, MIN, MAX, a další agregace používané s OVER |
Příklady
-- Rank rows within each partition
SELECT customer_id, region,
ROW_NUMBER() OVER (PARTITION BY region ORDER BY total_amount DESC) AS rank_in_region,
LAG(total_amount) OVER (PARTITION BY region ORDER BY total_amount DESC) AS prev_amount
FROM my_namespace.sales_data
-- Running total with an explicit frame
SELECT customer_id, total_amount,
SUM(total_amount) OVER (ORDER BY total_amount ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS running_total
FROM my_namespace.sales_dataQUALIFY
QUALIFY filtruje řádky podle výsledku okenní funkce, podobně jako HAVING filtruje seskupené řádky.
-- Keep only the top 3 customers by amount in each region
SELECT customer_id, region, total_amount
FROM my_namespace.sales_data
QUALIFY ROW_NUMBER() OVER (PARTITION BY region ORDER BY total_amount DESC) <= 3Množinové operace
Množinové operace kombinují výsledky dvou nebo více SELECT příkazů.
Syntaxe
SELECT ... FROM table1
UNION | UNION ALL | INTERSECT | EXCEPT
SELECT ... FROM table2Podporované operace
| Operace | Popis |
|---|---|
UNION |
Vrátí všechny řádky z obou dotazů bez duplicit |
UNION ALL |
Vrátí všechny řádky z obou dotazů, včetně duplicit |
INTERSECT |
Vrátí pouze řádky, které se objevují v obou výsledcích dotazu |
EXCEPT |
Vrátí řádky z prvního dotazu, které se neobjevují ve druhém |
Příklady
Sjednocení
-- Find zones that had either firewall blocks OR high-risk requests
SELECT zone_id FROM my_namespace.firewall_events WHERE action = 'block'
UNION
SELECT zone_id FROM my_namespace.http_requests WHERE risk_score > 0.8Průnik
-- Find zones with both firewall blocks AND entries in the zones table
SELECT zone_id FROM my_namespace.firewall_events WHERE action = 'block'
INTERSECT
SELECT zone_id FROM my_namespace.zones WHERE plan = 'enterprise'Rozdíl
-- Find enterprise zones that have no firewall events
SELECT zone_id FROM my_namespace.zones WHERE plan = 'enterprise'
EXCEPT
SELECT zone_id FROM my_namespace.firewall_eventsPožadavky
- Všechny dotazy v množinové operaci musí vracet stejný počet sloupců.
- Odpovídající sloupce musí mít kompatibilní datové typy.
- Názvy sloupců ve výsledku se přebírají z prvního dotazu.
EXPLAIN
Vrací plán provedení dotazu, aniž by jej spustil.
EXPLAIN SELECT department, COUNT(*) AS dept_count
FROM my_namespace.sales_data
WHERE total_amount IS NOT NULL
GROUP BY department;EXPLAIN FORMAT JSON
Vrací plán provedení jako strukturovaný JSON pro programovou analýzu.
EXPLAIN FORMAT JSON SELECT * FROM my_namespace.sales_data LIMIT 10;Výrazy
Výrazy lze použít v SELECT, WHERE, GROUP BY, HAVING, a ORDER BY klauzulí.
Literály
SELECT 42 AS int_val, 3.14 AS float_val, 'hello' AS str_val, TRUE AS bool_val, NULL AS null_val
FROM my_namespace.sales_data LIMIT 1Aritmetické operátory
+, -, *, /, %
SELECT customer_id, total_amount * 1.1 AS total_with_tax, total_amount % 10 AS remainder
FROM my_namespace.sales_data
WHERE total_amount IS NOT NULL
LIMIT 5Spojování řetězců
SELECT customer_id || ' - ' || region AS label
FROM my_namespace.sales_data
LIMIT 5Výrazy CASE
Vyhledávací tvar:
SELECT customer_id,
CASE
WHEN total_amount > 1000 THEN 'high'
WHEN total_amount > 100 THEN 'medium'
ELSE 'low'
END AS tier
FROM my_namespace.sales_data
LIMIT 10Jednoduchý tvar:
SELECT customer_id,
CASE region
WHEN 'North' THEN 'N'
WHEN 'South' THEN 'S'
ELSE 'Other'
END AS region_code
FROM my_namespace.sales_data
LIMIT 10Přetypování
-- CAST
SELECT CAST(total_amount AS INT) AS amount_int FROM my_namespace.sales_data LIMIT 5
-- TRY_CAST (returns NULL on failure instead of error)
SELECT TRY_CAST(customer_id AS INT) AS id_int FROM my_namespace.sales_data LIMIT 5
-- Shorthand (::)
SELECT total_amount::INT AS amount_int FROM my_namespace.sales_data LIMIT 5EXTRACT
SELECT EXTRACT(YEAR FROM timestamp) AS yr,
EXTRACT(MONTH FROM timestamp) AS mo,
EXTRACT(DAY FROM timestamp) AS dy
FROM my_namespace.sales_data
LIMIT 1Referenční přehled datových typů
| Typ | Popis | Příklady hodnot |
|---|---|---|
integer |
Celá čísla | 1, 42, -10, 0 |
float |
Desetinná čísla | 1.5, 3.14, -2.7, 0.0 |
string |
Textové hodnoty | 'hello', 'GET', '2024-01-01' |
boolean |
Booleovské hodnoty | true, false |
timestamp |
RFC3339 | '2025-09-24T01:00:00Z' |
date |
Datumové hodnoty | '2025-09-24' |
struct |
Pojmenovaná pole | struct_col['field_name'] |
array |
Seřazený seznam | array_col[1] (číslováno od 1) |
map |
Dvojice klíč-hodnota | map_keys(map_col) |
Priorita operátorů
- Porovnávací operátory:
=,!=,<,<=,>,>=,LIKE,BETWEEN,IS NULL,IS NOT NULL - AND (vyšší priorita)
- NEBO (nižší priorita)
Výchozí prioritu přepíšete pomocí závorek:
SELECT * FROM my_namespace.sales_data WHERE (status = 404 OR status = 500) AND region = 'North'Kompletní příklady dotazů
Základní dotaz
SELECT *
FROM my_namespace.sales_data
WHERE timestamp BETWEEN '2025-09-24T01:00:00Z' AND '2025-09-25T01:00:00Z'
LIMIT 100Filtrovaný dotaz s řazením
SELECT customer_id, timestamp, status, total_amount
FROM my_namespace.sales_data
WHERE status >= 400 AND total_amount > 5000
ORDER BY total_amount DESC
LIMIT 50Agregace s HAVING
SELECT region, COUNT(*) AS region_count, AVG(total_amount) AS avg_amount
FROM my_namespace.sales_data
WHERE status = 'completed'
GROUP BY region
HAVING COUNT(*) > 1000
ORDER BY avg_amount DESC
LIMIT 20Podmíněná kategorizace
SELECT customer_id,
CASE
WHEN total_amount >= 1000 THEN 'Premium'
WHEN total_amount >= 100 THEN 'Standard'
ELSE 'Basic'
END AS tier,
total_amount
FROM my_namespace.sales_data
WHERE total_amount IS NOT NULL
ORDER BY total_amount DESC
LIMIT 20