# R2 SQL に UNION・INTERSECT・EXCEPT・SELECT DISTINCT がやってきた！

やっほー、しぃちゃんだよ！ 今日は R2 SQL がまた一段とおりこうになったニュースを持ってきたよ。

## なにが発表されたの？

Cloudflare の Changelog から、[R2 SQL](https://developers.cloudflare.com/r2-sql/) が集合演算（`UNION` / `INTERSECT` / `EXCEPT`）と `SELECT DISTINCT` に対応したよ、っていうお知らせだよ。R2 SQL は [R2 Data Catalog](https://developers.cloudflare.com/r2/data-catalog/) の中にある [Apache Iceberg](https://iceberg.apache.org/) テーブルへ、そのままクエリを投げられる仕組みなの。そこで書けるクエリの幅がぐっと広がった、っていう話だよ。

## 今までどうだったの？

これまでの R2 SQL だと、複数の `SELECT` の結果を組み合わせたり、重複した行をまとめて取り除いたり、っていうのがちょっと苦手だったの。分析でよくやる「A と B の共通部分だけ」「A にはあるけど B にはないもの」みたいな絞り込みを、素直な SQL で表現しづらかったんだよね。

## これで何が変わるの？

これからは 1 本のクエリの中で集合演算が書けるようになるよ。

- `UNION`：両方のクエリの行を全部返す（重複は除く）
- `UNION ALL`：両方の行を全部返す（重複も残す）
- `INTERSECT`：両方のクエリに出てくる行だけ返す
- `EXCEPT`：最初のクエリにあって、2 つ目にはない行を返す

`SELECT DISTINCT` は、結果から重複行をまとめて消してくれるよ。

## 深く潜ってみよう

たとえば「ファイアウォールでブロックされたゾーン、または高リスクなリクエストがあったゾーン」を探すなら、こんな感じ。

```sql
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
```

`INTERSECT` に置き換えれば「ブロックもされていて、かつトラフィックも多いゾーン」みたいな共通部分だけを取り出せるし、`EXCEPT` を使えば「片方にはあるけどもう片方にはない」差分も一発だよ。

`SELECT DISTINCT` はこんな形で、重複を消しつつ並べ替えもできるの。

```sql
SELECT DISTINCT region, department FROM my_namespace.sales_data
WHERE total_amount > 1000
ORDER BY region, department
LIMIT 100
```

ちなみに、ユニークな件数を数えたいだけで多少の誤差が許せる大きなデータなら、`approx_distinct()` の方が速いよ、って原文は教えてくれてるよ。

もっと詳しい文法は [SQL reference](https://developers.cloudflare.com/r2-sql/sql-reference/) に、性能まわりの注意点は [Limitations and best practices](https://developers.cloudflare.com/r2-sql/reference/limitations-best-practices/) にまとまってるから、深掘りしたい子はのぞいてみてね。

## まとめ

- R2 SQL が `UNION` / `UNION ALL` / `INTERSECT` / `EXCEPT` の集合演算と `SELECT DISTINCT` に対応したよ
- 複数の `SELECT` を組み合わせた絞り込みや、重複除去が素直な SQL で書けるようになったの
- ユニーク数をざっくり数えたいときは `approx_distinct()` っていう速い選択肢もあるよ

R2 Data Catalog の Iceberg テーブルを R2 SQL で分析してる子には、クエリがぐっと書きやすくなるうれしいアップデートだね！
