DDLを仕上げる

作る順番が決まっている

ここまで、テーブルは必要になった順に足してきました。しかし本番環境を新しく立てるときや、テスト用のデータベースを作り直すときには、ゼロから通しで作れる DDL 一式が要ります。

そのとき初めて、順番の問題が出てきます。

CREATE TABLE orders ( store_id integer NOT NULL REFERENCES stores (id) ); -- ERROR relation "stores" does not exist

外部キーは、参照先のテーブルが先に存在していないと書けません。つまり DDL 一式の並び順は、参照の向きによって決まります。

依存を階層で捉える

並べ方は簡単です。誰も参照していないテーブルから始めて、参照している相手が全部そろったものを順に足していきます。

テーブル参照先
1段目prefectures, categories, customers無し
2段目stores, products1段目
3段目product_tags, orders2段目
4段目order_items, inventories, shipments3段目

同じ段の中の順番はどれでも構いません。段の順番だけが決まっている、という捉え方をすると迷いません。

順番を考えたくない場合

外部キーを CREATE TABLE の中に書かず、全テーブルを作ってから ALTER TABLE ... ADD CONSTRAINT でまとめて足す書き方もあります。

書き方利点欠点
CREATE の中に書く定義が1か所にまとまる作成順を守る必要がある
あとから ALTER で足す順番を気にしなくてよい定義が2か所に分かれる

手で書く設計書としては前者が読みやすく、機械が出力する移行スクリプトでは後者がよく使われます。読む相手が人か機械かで選びます。

消す順番は逆になる

作り直すときは削除もします。削除の順番は作成の逆、つまり参照している側からです。

DROP TABLE IF EXISTS order_items; DROP TABLE IF EXISTS orders; DROP TABLE IF EXISTS customers;

IF EXISTS を付けておくと、まだ無いテーブルを消そうとしてもエラーになりません。何度流しても同じ結果になる、という性質は移行スクリプトで重要です。

手を動かす

1段目の2テーブルだけが用意されています。残りを正しい順番で作り切ります。

テーブル構造

CREATE TABLE prefectures ( pref text PRIMARY KEY, region text NOT NULL ); CREATE TABLE categories ( id integer PRIMARY KEY, name text NOT NULL );

期待される出力

table_countfk_count
1010

ヒント

query.sql
学習モード
コードの実行結果
データベースを初期化中...