【実務・中級編】 配列型(Array Types) – PostgreSQL

おい、そこの君! PostgreSQLの配列型、ちょっと触ってみたんだけど、なんか奥が深くて迷子になりそう? 大丈夫、俺も最初はそうだったんだ。でもね、これ、使い方次第でめちゃくちゃ便利になるんだぜ。今日は、現場で「これ知っててよかった!」って思うような、配列型の実践的な使い方を、先輩エンジニアの俺が優しく、でもちょっと熱く語ってやるから、しっかりついてきてくれよな!

PostgreSQLの配列型、ぶっちゃけどうなの?

まず、そもそも配列型って何? っていう基本から。簡単に言うと、同じデータ型の値を複数まとめて格納できるデータ型のことだ。例えば、ユーザーの好きな食べ物のリストとか、商品のタグ一覧とか、そういう「複数個あるもの」をきれいに格納したいときに役立つんだ。

PostgreSQLでは、 pretty much どんなデータ型でも配列にできる。整数型、文字列型、日付型、JSON型、さらには自分で作ったカスタム型だってOKだ。これがまた、SQLの柔軟性をグッと上げてくれるんだよな。

多次元配列? できますよ、奥さん!

「配列の中に配列を入れたらどうなるの?」って思った? いい質問だ! PostgreSQLは多次元配列もサポートしてるんだ。例えば、2次元配列なら、表形式のデータをそのまま格納できたりする。

CREATE TABLE board (
id SERIAL PRIMARY KEY,
game_board INTEGER[][] — 2次元配列
);

INSERT INTO board (game_board) VALUES
(‘{{1,0,0},{0,1,0},{0,0,1}}’);

こんな感じで、チェス盤とか、マスの状態を表すのに便利だったりする。まあ、多次元配列は使いどころを間違えると、後で自分で地獄を見る羽目になることもあるから、そこは注意が必要だけどな!

現場で役立つ!配列型の具体的な使い方

さて、ここからが本番だ。実際の現場で、配列型がどう役立つのか、具体的な例を交えて見ていこう。

1. 配列の連結(`||`演算子)

複数の配列をくっつけたいとき、どうする? 簡単、`||`演算子を使えばいいんだ。

例えば、ユーザーの「過去の注文ID」と「現在の注文ID」をまとめて管理したい場合なんかだ。

SELECT ARRAY[101, 102] || ARRAY[103, 104];
— 結果: {101, 102, 103, 104}

これなら、`UNION ALL`とかでゴチャゴチャやるよりも、ずっとスマートに書けるだろ?

2. 配列のスライス(`[開始:終了]`)

配列の一部だけを取り出したい、なんて場面もあるよな。そんなときはスライス機能だ。

例えば、商品のタグリストから、最初の3つだけ欲しいときとか。

SELECT ARRAY[‘apple’, ‘banana’, ‘cherry’, ‘date’, ‘elderberry’][1:3];
— 結果: {apple, banana, cherry}

インデックスは1から始まるから、ちょっと戸惑うかもしれないけど、慣れれば簡単だ。
「え、0からじゃないの?」って思った? いいんだよ、PostgreSQLは1からなんだ。そこ、テストに出るぞ! (嘘だけど、覚えておくと便利だ)

3. 要素の検索(`ANY`演算子や`@>`演算子)

「この配列の中に、特定の要素が含まれているかどうかを知りたい」って、これ、めちゃくちゃよくある要件だろ?

例えば、ユーザーが特定の「興味」を持っているかどうかをチェックしたいときなんかだ。

  • `ANY`演算子: 配列のいずれかの要素が条件を満たすかどうかをチェックする。

SELECT FROM users WHERE ‘programming’ = ANY(interests);

これは、「`interests`配列の中に`’programming’`という要素があれば、その行をSELECTする」って意味になる。シンプルで分かりやすいだろ?

  • `@>`演算子(Contains演算子): 左側の配列が、右側の配列の全ての要素を含んでいるかどうかをチェックする。

SELECT FROM products WHERE tags @> ARRAY[‘electronics’, ‘sale’];

これは、「`tags`配列が`’electronics’`と`’sale’`の両方を含んでいれば、その行をSELECTする」って意味だ。複数の条件をまとめてチェックしたいときに便利なんだ。

逆に、`@<`演算子で「含まれているか」をチェックすることもできる。この演算子、記号がちょっと紛らわしいから、最初は戸惑うかもな。でも、一度覚えてしまえば、強力な武器になるぞ。

4. `array_agg()`関数 – 集計結果を配列に!

これ、マジで便利! 複数の行にまたがったデータを、一つの配列にまとめてくれる機能だ。

例えば、あるカテゴリに属する全商品の名前をリストアップしたいときとか。

CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
category VARCHAR(50)
);

INSERT INTO products (name, category) VALUES
(‘Laptop’, ‘electronics’),
(‘Keyboard’, ‘electronics’),
(‘Mouse’, ‘electronics’),
(‘Desk Chair’, ‘furniture’);

SELECT category, array_agg(name) AS product_names
FROM products
GROUP BY category;

このクエリを実行すると、こんな結果が得られるはずだ。

category | product_names
————-+———————–
electronics | {Laptop,Keyboard,Mouse}
furniture | {Desk Chair}

どうだ? 劇的に見やすくなっただろ? これで、アプリケーション側でいちいちループして配列を作る手間が省けるんだ。

5. `unnest()`関数 – 配列をバラバラにして行に!

`array_agg()`の逆バージョンだと思ってもらっていい。配列の要素を、それぞれ別々の行に展開してくれるんだ。

例えば、さっきの`product_names`配列を、もう一度個別の商品名に戻したいときとか。

SELECT id, unnest(product_names) AS product_name
FROM (
SELECT category, array_agg(name) AS product_names
FROM products
GROUP BY category
) AS subquery;

これを使えば、配列の中に埋もれていたデータも、簡単に取り出して扱えるようになる。データの「正規化」と「非正規化」を、SQLの中で柔軟に行えるようになるってことだ。

配列型を使う上での注意点

ここまで良いことばかり言ってきたけど、もちろん注意点もある。

  • インデックス: 配列型カラムにインデックスを貼る場合、通常のインデックスとは少し違う。GISTインデックスやGINインデックスを使うことで、配列内の要素検索や範囲検索を高速化できる。どんなインデックスが適しているかは、クエリのパターンによって変わってくるから、そこはしっかり検証が必要だ。
  • NULL値: 配列内にNULL値を入れることもできる。ただし、NULL値の扱いは、後で自分でクエリを書くときに意識しておかないと、意図しない結果になることもあるから注意しろよ。
  • パフォーマンス: あまりに巨大な配列を頻繁に更新したり、複雑な配列操作を繰り返したりすると、パフォーマンスに影響が出ることもある。ユースケースに応じて、本当に配列型が最適なのか、他の正規化されたテーブル構造の方が良いのか、検討することは重要だ。

まとめ – 配列型は「賢く」使おう

PostgreSQLの配列型は、うまく使えば開発効率を上げ、コードをシンプルにしてくれる強力なツールだ。今回紹介した機能以外にも、まだまだ奥深い機能はたくさんある。

でも、何でもかんでも配列型にすればいいってもんじゃない。データ構造の基本原則(正規化とかね)も忘れずに、それぞれのデータに合った最適なモデリングを心がけることが大事だ。

今日の話で、君も配列型マスターに一歩近づいたはずだ。あとは、実際に手を動かして、色々なケースで試してみることだ。もし分からないことがあったら、いつでも俺に聞きに来いよ! じゃ、またな!

コメント

タイトルとURLをコピーしました