INTEGRITY Dokumentace

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

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 10

DISTINCT

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 DESC

Pro 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_name

Zř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 DESC

CTE 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 20

Dvě 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 20

Klauzule FROM

Syntaxe

SELECT * FROM namespace_name.table_name

Dotazy 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.column

Ví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 20

Self 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 20

Podmínky spojení

Doporučené postupy pro spojení


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 20

Odvozené 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 20

IN / 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 10

EXISTS / 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 20

Skalá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 20

Klauzule WHERE

Syntaxe

SELECT * FROM namespace_name.table_name WHERE condition [AND | OR condition ...]

Podmínky

Porovnávací operátory

=, !=, <>, <, >, <=, >=

Kontrola hodnot NULL

Booleovské kontroly

Rozsah

Členství v seznamu

Porovnávání vzorů

Logické operátory

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_list

Pří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, category

GROUPING 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.

-- 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 value

Pří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) > 1000000

Klauzule ORDER BY

Syntaxe

ORDER BY expression [ASC | DESC] [, expression [ASC | DESC], ...]

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 ASC

Klauzule LIMIT

Syntaxe

LIMIT number

Příklady

SELECT * FROM my_namespace.sales_data LIMIT 100

Okenní 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_data

QUALIFY

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) <= 3

Množ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 table2

Podporované 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.8

Prů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_events

Požadavky


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 1

Aritmetické 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 5

Spojování řetězců

SELECT customer_id || ' - ' || region AS label
FROM my_namespace.sales_data
LIMIT 5

Vý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 10

Jednoduchý 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 10

Př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 5

EXTRACT

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 1

Referenč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ů

  1. Porovnávací operátory: =, !=, <, <=, >, >=, LIKE, BETWEEN, IS NULL, IS NOT NULL
  2. AND (vyšší priorita)
  3. 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 100

Filtrovaný 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 50

Agregace 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 20

Podmí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