たまに、「ある値の集合が別の集合に含まれてるか?」「重なりがあるか?」「完全に一致してる?」「部分集合か?」みたいなシチュエーションが出てくるよね。例えば:
- ユーザーが特定カテゴリへのアクセス権を持ってる?
- どの商品が共通のタグを持ってる?
- どの配列が全部の指定値を含んでる?
こういうのはPostgreSQLの配列比較オペレーター=、@>、<@、&&で解決できる。これらのオペレーターを一つずつ例で見ていこう!
= — 配列の等価比較
このオペレーターは、2つの配列が完全に同じかどうかをチェックするやつ。両方の配列が同じ長さで、同じ順番・同じ要素ならTRUEになる。
例:
SELECT ARRAY[1, 2, 3] = ARRAY[1, 2, 3] AS are_equal; -- TRUE
SELECT ARRAY[1, 2, 3] = ARRAY[3, 2, 1] AS are_equal; -- FALSE
ポイント: 要素の順番が大事。配列[1, 2, 3]は[3, 2, 1]と等しくないよ。
@> — 配列が他の配列を含む
このオペレーターは、配列が別の配列の全要素を(順番関係なく)含んでるかをチェックする。全部入ってるか確認したい時によく使う。
例:
SELECT ARRAY[1, 2, 3] @> ARRAY[1, 2] AS contains; -- TRUE
SELECT ARRAY[1, 2, 3] @> ARRAY[4] AS contains; -- FALSE
便利な使い方: アクセス権チェックとか。例えば、あるロールが必要な権限を全部持ってるか確認したい時とかね。
<@ — 配列が他の配列の部分集合か
@>の逆バージョン。配列が完全に他の配列の中に含まれてるかをチェックする。
例:
SELECT ARRAY[1, 2] <@ ARRAY[1, 2, 3] AS is_subset; -- TRUE
SELECT ARRAY[4] <@ ARRAY[1, 2, 3] AS is_subset; -- FALSE
便利な使い方: テーブルの特定行が全部の必要なラベルやカテゴリを持ってるか確認したい時とか。
&& — 配列の重なり(交差)
このオペレーターは、2つの配列に少なくとも1つ共通要素があるかどうかを調べる。
例:
SELECT ARRAY[1, 2, 3] && ARRAY[3, 4, 5] AS intersects; -- TRUE
SELECT ARRAY[1, 2, 3] && ARRAY[6, 7, 8] AS intersects; -- FALSE
便利な使い方: 共通カテゴリや特徴を持つ商品やレコードを探す時に使えるよ。
データフィルタリングでのオペレーター活用
これらのオペレーターを使ってテーブルのデータをフィルタリングしてみよう。例えば、productsテーブルがあって、tagsカラムに各商品のタグ配列が入ってるとする。
productsテーブル例
| id | name | tags |
|---|---|---|
| 1 | "Product A" | {electronics, sale} |
| 2 | "Product B" | {home, sale} |
| 3 | "Product C" | {electronics, new} |
| 4 | "Product D" | {home, garden} |
タグelectronicsを持つ商品を全部探そう。
SELECT *
FROM products
WHERE tags @> ARRAY['electronics'];
結果:
| id | name | tags |
|---|---|---|
| 1 | "Product A" | {electronics, sale} |
| 3 | "Product C" | {electronics, new} |
タグがちょうど{home, sale}の商品のみを探したい。
SELECT *
FROM products
WHERE tags = ARRAY['home', 'sale'];
結果:
| id | name | tags |
|---|---|---|
| 2 | "Product B" | {home, sale} |
じゃあ今度は
タグが{sale, new}のどちらか一つでも含まれてる商品を探そう。SELECT *
FROM products
WHERE tags && ARRAY['sale', 'new'];
結果:
| id | name | tags |
|---|---|---|
| 1 | "Product A" | {electronics, sale} |
| 2 | "Product B" | {home, sale} |
| 3 | "Product C" | {electronics, new} |
タグがちょうど{home, garden}に限定されてる商品を探す。
SELECT *
FROM products
WHERE tags <@ ARRAY['home', 'garden'];
結果:
| id | name | tags |
|---|---|---|
| 4 | "Product D" | {home, garden} |
例: CASEでリスト内容を判定
配列比較と条件式を組み合わせることもできる。例えば、タグにsaleが入ってたら「割引」、それ以外は「割引なし」と表示するクエリを作ってみよう:
SELECT name,
CASE
WHEN tags @> ARRAY['sale'] THEN '割引'
ELSE '割引なし'
END AS discount_status
FROM products;
結果:
| name | discount_status |
|---|---|
| "Product A" | 割引 |
| "Product B" | 割引 |
| "Product C" | 割引なし |
| "Product D" | 割引なし |
よくあるミスとその回避法
ミス: =で順番を間違えて使う。 =は要素の順番まで完全一致じゃないとダメ。順番がどうでもいいなら@>や&&を使おう。
ミス: データ型の不一致。 配列は同じ型じゃないと比較できない。例えばARRAY['1', '2']はARRAY[1, 2]と等しくない。前もって型をチェックしよう。
ミス: インデックスなし。 配列でよくフィルタするなら、パフォーマンスのためにGINインデックスを作っておこう。
これらのオペレーターを使えば、商品タグ分析やアクセス権管理など、実際のプロジェクトでよく出てくる配列データの強力な比較・フィルタリングができる。うまく使いこなして、複雑な処理もシンプル&高速にしよう!
GO TO FULL VERSION