PostgreSQL | SQLite+MySQL経験者向け、30日で習得するPostgreSQL:差分理解 - Day3 データ型の理解

SQL PostgreSQL
スポンサーリンク

Day3 前半のゴール

「“なんとなく文字列・なんとなく日付”から卒業する」

今日は PostgreSQL の代表的なデータ型のうち、
文字列(TEXT / VARCHAR)、真偽値(BOOLEAN)、日時(TIMESTAMP)に絞って話します。

前半のゴールはこうです。
TEXT と VARCHAR の違いを、「どっちをいつ選ぶか」というレベルで説明できる。
BOOLEAN が「0/1 ではなく true/false を素直に扱える型」だと理解できる。
TIMESTAMP が「ただの文字列日付」ではなく、「時間として計算できる値」だとイメージできる。

SQLite や MySQL で「とりあえず TEXT」「とりあえず VARCHAR(255)」と書いていた感覚を、
PostgreSQL では一段整理していきます。


TEXT / VARCHARの違いを整理する

「“技術的な違い”より“設計としての意図”が大事」

まずは、文字列型です。
PostgreSQL では、代表的にこういう型があります。

TEXT
VARCHAR(n)
VARCHAR(長さ指定なし)

SQLite では「全部 TEXT でいいや」となりがちでした。
MySQL では「とりあえず VARCHAR(255)」がよく出てきたと思います。

PostgreSQL では、実は TEXT と VARCHAR(長さ指定なし)は、性能面ではほぼ同じように扱われます。
「TEXTだから遅い」「VARCHARだから速い」といった差は、基本的に気にしなくてOKです。

じゃあ何が違うのかというと、「長さ制約を付けるかどうか」です。

VARCHAR(n) は「長さの上限を設計として決める」ためのもの

例えば、ユーザー名を入れるカラムを考えます。

CREATE TABLE users (
  id       SERIAL PRIMARY KEY,
  name     VARCHAR(50) NOT NULL
);
SQL

ここで VARCHAR(50) と書くのは、「ユーザー名は最大50文字まで」という“ルール”をDB側に持たせる、という意味です。

もしアプリ側のバリデーション漏れで、100文字の名前が飛んできたら、
PostgreSQLは「長すぎるよ」とエラーを返してくれます。

一方で、ブログ記事の本文や、エラーログのメッセージなど、
「長さをあまり気にせず、好きなだけ入れたい」ものは TEXT にするのが自然です。

CREATE TABLE posts (
  id       SERIAL PRIMARY KEY,
  title    VARCHAR(200) NOT NULL,
  body     TEXT NOT NULL
);
SQL

title は「ある程度の上限を決めたい」ので VARCHAR(200)、
body は「長くてもいい」ので TEXT、という分け方です。

ここでの重要ポイントは、
「TEXTかVARCHARかは性能の話ではなく、“どこまでをDBに守らせるか”という設計の話」
だと捉えることです。


BOOLEAN型をちゃんと使う意味

「0/1 や ‘Y’/’N’ から、“true/false”の世界へ」

次に BOOLEAN 型です。
SQLite では BOOLEAN という型は実質なく、0/1 や TEXT で代用していたはずです。
MySQL でも、BOOLEAN は実体としては TINYINT(1) だったりします。

PostgreSQL には、ちゃんと BOOLEAN 型があります。

CREATE TABLE users (
  id        SERIAL PRIMARY KEY,
  name      TEXT NOT NULL,
  is_active BOOLEAN NOT NULL
);
SQL

ここにデータを入れるとき、PostgreSQLではこう書けます。

INSERT INTO users (name, is_active)
VALUES ('Taro', true),
       ('Jiro', false);
SQL

true / false を、そのまま値として扱えます。
また、0/1 や ‘t’/’f’ なども受け付けてくれますが、
「読みやすさ」という意味では true / false を素直に使うのがおすすめです。

条件式が“人間の言葉”に近づく

BOOLEAN をちゃんと使うと、WHERE句も読みやすくなります。

SELECT * FROM users WHERE is_active = true;
SQL

あるいは、もっとシンプルに、

SELECT * FROM users WHERE is_active;
SQL

と書くこともできます(is_active が true の行だけが返る)。

MySQLで「フラグを TINYINT(1) で持って、0/1 で判定する」スタイルに慣れていると、
最初は違和感があるかもしれませんが、
「is_active が true かどうか」と書けるのは、かなり気持ちがいいです。

ここでのポイントは、
「BOOLEAN をちゃんと使うと、SQLが“ビジネスルールの文章”に近づく」
ということです。


TIMESTAMP型のイメージを固める

「“文字列の日付”ではなく、“時間として計算できる値”」

最後に TIMESTAMP です。
これは「日時」を表す型で、PostgreSQLでは大きく2種類あります。

TIMESTAMP(タイムゾーンなし)
TIMESTAMPTZ(タイムゾーン付き)

Day3 前半では、まず「タイムゾーンなしのTIMESTAMP」を中心にイメージを固めます。

例えば、ユーザーの作成日時・更新日時を持つテーブルは、こう書けます。

CREATE TABLE users (
  id         SERIAL PRIMARY KEY,
  name       TEXT NOT NULL,
  created_at TIMESTAMP NOT NULL,
  updated_at TIMESTAMP NOT NULL
);
SQL

ここにデータを入れるとき、よくやるのは NOW() を使う方法です。

INSERT INTO users (name, created_at, updated_at)
VALUES ('Taro', NOW(), NOW());
SQL

NOW() は「現在の日時」を TIMESTAMP 型で返してくれます。

文字列ではなく“時間として扱える”ことが大事

TIMESTAMP の良さは、「時間として計算できる」ことです。

例えば、「直近7日以内に作成されたユーザーを取りたい」とします。

SELECT *
FROM users
WHERE created_at >= NOW() - INTERVAL '7 days';
SQL

ここでは、「現在時刻から7日引いた日時」以上のもの、という条件を書いています。
これが、もし created_at を TEXT で持っていたら、こういう計算はかなり面倒になります。

PostgreSQLでは、「日時はTIMESTAMPで持つ」「期間はINTERVALで表す」というのが基本スタイルです。
これに慣れると、「時間に関するクエリ」が一気に書きやすくなります。


Day3 前半のまとめ

PostgreSQLの文字列型では、TEXT と VARCHAR は性能差よりも「長さ制約をDBに持たせるかどうか」が本質で、ユーザー名やタイトルのように上限を決めたいものは VARCHAR(n)、本文やログのように長さをあまり気にしないものは TEXT として、「どこまでをDBに守らせるか」を設計として決める。
BOOLEAN 型は、0/1 や ‘Y’/’N’ の代わりに true / false をそのまま扱える型で、is_active のようなフラグを BOOLEAN で定義すると、WHERE is_active のように“人間の言葉に近い条件式”を書けるようになり、SQLの可読性が上がる。
TIMESTAMP は「文字列の日付」ではなく「時間として計算できる値」であり、created_at TIMESTAMPNOW() を入れておけば、WHERE created_at >= NOW() - INTERVAL '7 days' のように「直近7日」のような条件を自然に書けるようになる――この3つの型のイメージをしっかり持つことが Day3 前半の着地点になる。

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