PostgreSQL CLI完全チートシート:現場開発でよく使うコマンド集

2025/09/07に公開

PostgreSQL開発において、「あのコマンドなんだっけ?」と思う瞬間は誰にでもあります。本記事では、現場開発で実際によく使用するPostgreSQLコマンドを実用性重視でまとめました。

初心者エンジニアから中級者まで、開発現場ですぐに使える実践的なチートシートとして活用してください。

PostgreSQLへの接続・切断

基本的な接続

ターミナル
# ローカルのpostgresユーザーで接続 psql -U postgres # 特定のデータベースに接続 psql -U username -d database_name # リモートサーバーに接続 psql -h hostname -U username -d database_name -p 5432 # 接続URLを使用した接続 psql "postgresql://username:password@hostname:5432/database_name"

環境変数を利用した接続

ターミナル
# 環境変数設定 export PGHOST=localhost export PGPORT=5432 export PGUSER=myuser export PGDATABASE=mydb # 環境変数を使って接続 psql

接続オプション

ターミナル
# パスワードプロンプトを表示 psql -U username -W # SSL接続を強制 psql "sslmode=require host=hostname user=username dbname=database_name" # 接続タイムアウトを設定 psql -c "SET statement_timeout = 30000;" -U username database_name

切断

-- psqlからの切断 \q -- または \quit -- 他のセッションを強制終了 SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE usename = 'username' AND pid <> pg_backend_pid();

データベースとスキーマの操作

データベース一覧と詳細

-- データベース一覧 \l \list -- 詳細情報付きでデータベース一覧 \l+ -- 現在のデータベース情報 SELECT current_database(); -- データベースのサイズ確認 SELECT datname, pg_size_pretty(pg_database_size(datname)) AS size FROM pg_database ORDER BY pg_database_size(datname) DESC;

データベース作成・削除

-- データベース作成 CREATE DATABASE myapp_development; -- エンコーディング指定でデータベース作成 CREATE DATABASE myapp_production WITH ENCODING 'UTF8' LC_COLLATE='ja_JP.UTF-8' LC_CTYPE='ja_JP.UTF-8'; -- テンプレートを指定してデータベース作成 CREATE DATABASE new_db WITH TEMPLATE template0; -- データベース削除(接続を強制切断) SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'database_to_drop'; DROP DATABASE database_to_drop;

スキーマ操作

-- スキーマ一覧 \dn \dn+ -- スキーマ作成 CREATE SCHEMA app_schema; -- スキーマ削除(CASCADE注意) DROP SCHEMA app_schema CASCADE; -- 検索パス確認・設定 SHOW search_path; SET search_path TO app_schema, public; -- デフォルトスキーマ設定 ALTER DATABASE myapp SET search_path = app_schema, public;

データベース切り替え

-- データベース切り替え \c database_name \connect database_name -- 別のユーザーで切り替え \c database_name username

テーブル操作(構造確認・作成・削除)

テーブル一覧と構造確認

-- テーブル一覧 \dt \dt *.* -- 全スキーマのテーブル -- テーブル詳細情報 \dt+ -- 特定テーブルの構造確認 \d table_name \d+ table_name -- 詳細情報付き -- テーブルのカラム情報のみ \d+ table_name -- インデックス情報 \di table_name

テーブル作成

-- 基本的なテーブル作成 CREATE TABLE users ( id SERIAL PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, name VARCHAR(100) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 制約付きテーブル作成 CREATE TABLE orders ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id) ON DELETE CASCADE, amount DECIMAL(10,2) CHECK (amount > 0), status VARCHAR(20) DEFAULT 'pending', order_date DATE NOT NULL, CONSTRAINT valid_status CHECK (status IN ('pending', 'completed', 'cancelled')) ); -- パーティションテーブル CREATE TABLE sales ( id SERIAL, sale_date DATE, amount DECIMAL(10,2) ) PARTITION BY RANGE (sale_date);

テーブル変更

-- カラム追加 ALTER TABLE users ADD COLUMN phone VARCHAR(20); -- カラム削除 ALTER TABLE users DROP COLUMN phone; -- カラム名変更 ALTER TABLE users RENAME COLUMN name TO full_name; -- カラムデータ型変更 ALTER TABLE users ALTER COLUMN email TYPE TEXT; -- NOT NULL制約追加 ALTER TABLE users ALTER COLUMN email SET NOT NULL; -- デフォルト値設定 ALTER TABLE users ALTER COLUMN created_at SET DEFAULT NOW(); -- 制約追加 ALTER TABLE users ADD CONSTRAINT email_check CHECK (email ~* '^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+[.][A-Za-z]+$');

テーブル削除・切り捨て

-- テーブル削除 DROP TABLE table_name; DROP TABLE IF EXISTS table_name; -- 外部キー制約無視して削除 DROP TABLE table_name CASCADE; -- テーブルデータのみ削除 TRUNCATE TABLE table_name; TRUNCATE TABLE table_name RESTART IDENTITY CASCADE;

データ操作(CRUD)

データ挿入(INSERT)

-- 基本的な挿入 INSERT INTO users (email, name) VALUES ('user@example.com', 'John Doe'); -- 複数行一括挿入 INSERT INTO users (email, name) VALUES ('user1@example.com', 'User One'), ('user2@example.com', 'User Two'), ('user3@example.com', 'User Three'); -- SELECT結果から挿入 INSERT INTO user_backup SELECT * FROM users WHERE created_at < '2024-01-01'; -- 競合時の処理(PostgreSQL 9.5+) INSERT INTO users (email, name) VALUES ('user@example.com', 'John Doe') ON CONFLICT (email) DO NOTHING; INSERT INTO users (email, name) VALUES ('user@example.com', 'John Updated') ON CONFLICT (email) DO UPDATE SET name = EXCLUDED.name, updated_at = CURRENT_TIMESTAMP;

データ取得(SELECT)

-- 基本的な取得 SELECT * FROM users; SELECT id, email, name FROM users WHERE id = 1; -- 条件付き取得 SELECT * FROM users WHERE created_at >= '2024-01-01'; SELECT * FROM users WHERE name LIKE '%John%'; SELECT * FROM users WHERE email ~ '@gmail\.com$'; -- ソート・制限 SELECT * FROM users ORDER BY created_at DESC LIMIT 10; SELECT * FROM users ORDER BY name OFFSET 20 LIMIT 10; -- 集計 SELECT COUNT(*) FROM users; SELECT DATE(created_at), COUNT(*) FROM users GROUP BY DATE(created_at) ORDER BY DATE(created_at); -- 結合 SELECT u.name, COUNT(o.id) as order_count FROM users u LEFT JOIN orders o ON u.id = o.user_id GROUP BY u.id, u.name;

データ更新(UPDATE)

-- 基本的な更新 UPDATE users SET name = 'Updated Name' WHERE id = 1; -- 複数カラム更新 UPDATE users SET name = 'New Name', updated_at = CURRENT_TIMESTAMP WHERE id = 1; -- 条件付き更新 UPDATE users SET name = 'VIP User' WHERE id IN (SELECT user_id FROM orders GROUP BY user_id HAVING COUNT(*) > 10); -- JOINを使った更新 UPDATE users SET status = 'active' FROM orders WHERE users.id = orders.user_id AND orders.created_at >= '2024-01-01';

データ削除(DELETE)

-- 基本的な削除 DELETE FROM users WHERE id = 1; -- 条件付き削除 DELETE FROM users WHERE created_at < '2024-01-01'; -- JOINを使った削除 DELETE FROM users USING orders WHERE users.id = orders.user_id AND orders.status = 'cancelled';

ユーザーと権限管理

ユーザー一覧と詳細

-- ユーザー一覧 \du \du+ -- 詳細なユーザー情報 SELECT usename, usesuper, usecreatedb, useconnlimit FROM pg_user; -- 現在のユーザー確認 SELECT current_user; SELECT session_user;

ユーザー作成・削除

-- 基本的なユーザー作成 CREATE USER app_user WITH PASSWORD 'secure_password'; -- 権限付きユーザー作成 CREATE USER admin_user WITH PASSWORD 'admin_pass' CREATEDB CREATEROLE; -- ロール作成(ログイン不可) CREATE ROLE app_role; -- ユーザー削除 DROP USER app_user; -- 権限の有効期限設定 CREATE USER temp_user WITH PASSWORD 'temp_pass' VALID UNTIL '2024-12-31';

権限管理

-- データベースへのアクセス権付与 GRANT CONNECT ON DATABASE myapp TO app_user; -- スキーマへのアクセス権 GRANT USAGE ON SCHEMA public TO app_user; -- テーブルへの権限付与 GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user; -- 新しく作成されるテーブルへの権限 ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_user; -- 権限取り消し REVOKE DELETE ON users FROM app_user; -- 権限確認 \dp table_name SELECT grantee, privilege_type FROM information_schema.role_table_grants WHERE table_name='users';

ロール管理

-- ロール作成 CREATE ROLE readonly; CREATE ROLE readwrite; -- ロールに権限付与 GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly; GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO readwrite; -- ユーザーにロール付与 GRANT readonly TO app_user; -- ロール確認 SELECT rolname FROM pg_roles WHERE pg_has_role('app_user', oid, 'member');

バックアップとリストア

pg_dumpを使ったバックアップ

ターミナル
# データベース全体のバックアップ pg_dump -U username -h hostname database_name > backup.sql # 圧縮バックアップ pg_dump -U username -h hostname database_name | gzip > backup.sql.gz # カスタムフォーマットでバックアップ pg_dump -U username -h hostname -Fc database_name > backup.dump # 特定テーブルのみバックアップ pg_dump -U username -h hostname -t table_name database_name > table_backup.sql # スキーマのみバックアップ pg_dump -U username -h hostname -s database_name > schema_backup.sql # データのみバックアップ pg_dump -U username -h hostname -a database_name > data_backup.sql

pg_dumpallを使った全データベースバックアップ

ターミナル
# 全データベースのバックアップ pg_dumpall -U postgres > all_databases.sql # ロールとテーブル空間のみ pg_dumpall -U postgres -r > roles.sql

リストア

ターミナル
# SQLファイルからリストア psql -U username -h hostname database_name < backup.sql # 圧縮ファイルからリストア gunzip -c backup.sql.gz | psql -U username -h hostname database_name # カスタムフォーマットからリストア pg_restore -U username -h hostname -d database_name backup.dump # 並列リストア(高速化) pg_restore -U username -h hostname -d database_name -j 4 backup.dump # 特定テーブルのみリストア pg_restore -U username -h hostname -d database_name -t table_name backup.dump

継続的バックアップ(WAL)

ターミナル
# WALアーカイブの設定確認 SHOW archive_mode; SHOW archive_command; # ベースバックアップ作成 pg_basebackup -D /backup/base -Ft -z -P # PITR(Point-in-Time Recovery)用設定 SELECT pg_start_backup('backup_label'); -- ファイルシステムレベルでコピー SELECT pg_stop_backup();

パフォーマンス監視

実行中のクエリ監視

-- 実行中のクエリ一覧 SELECT pid, now() - pg_stat_activity.query_start AS duration, query FROM pg_stat_activity WHERE (now() - pg_stat_activity.query_start) > interval '5 minutes'; -- 長時間実行中のクエリ強制終了 SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE pid = <process_id>; -- アクティブな接続数 SELECT count(*) FROM pg_stat_activity; -- データベース別接続数 SELECT datname, count(*) FROM pg_stat_activity GROUP BY datname;

テーブル統計情報

-- テーブルのアクセス統計 SELECT schemaname, tablename, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del FROM pg_stat_user_tables ORDER BY seq_tup_read DESC; -- インデックス使用状況 SELECT schemaname, tablename, indexname, idx_scan, idx_tup_read, idx_tup_fetch FROM pg_stat_user_indexes ORDER BY idx_scan DESC; -- 使用されていないインデックス SELECT schemaname, tablename, indexname, idx_scan FROM pg_stat_user_indexes WHERE idx_scan = 0;

パフォーマンス分析

-- スロークエリ分析(pg_stat_statements拡張必要) SELECT query, calls, total_time, mean_time, rows FROM pg_stat_statements ORDER BY mean_time DESC LIMIT 10; -- クエリ実行計画 EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'user@example.com'; -- バッファキャッシュヒット率 SELECT sum(heap_blks_read) as heap_read, sum(heap_blks_hit) as heap_hit, sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) as ratio FROM pg_statio_user_tables;

システム情報

-- データベースサイズ SELECT datname, pg_size_pretty(pg_database_size(datname)) AS size FROM pg_database; -- テーブルサイズ SELECT tablename, pg_size_pretty(pg_total_relation_size(tablename::regclass)) AS size FROM pg_tables WHERE schemaname = 'public' ORDER BY pg_total_relation_size(tablename::regclass) DESC; -- 設定値確認 SHOW all; SHOW shared_buffers; SHOW effective_cache_size;

便利なメタコマンド(\dシリーズ)

基本的なメタコマンド

-- ヘルプ \? -- メタコマンドヘルプ \h -- SQLコマンドヘルプ \h SELECT -- 特定SQLのヘルプ -- 接続情報 \conninfo -- 現在の接続情報 \c -- データベース切り替え -- 終了 \q -- 終了

構造確認系メタコマンド

-- データベースとスキーマ \l -- データベース一覧 \dn -- スキーマ一覧 \du -- ユーザー一覧 -- テーブルとビュー \dt -- テーブル一覧 \dt+ -- テーブル詳細一覧 \dv -- ビュー一覧 \dm -- マテリアライズドビュー一覧 \ds -- シーケンス一覧 -- インデックスと制約 \di -- インデックス一覧 \di+ -- インデックス詳細一覧 -- 関数とプロシージャ \df -- 関数一覧 \df+ -- 関数詳細 \dp -- 権限確認

特定オブジェクトの詳細

-- テーブル構造 \d table_name -- テーブル構造 \d+ table_name -- 詳細なテーブル構造 \dt *table_name* -- テーブル名を部分検索 -- インデックス詳細 \di table_name -- 特定テーブルのインデックス -- 関数詳細 \df function_name -- 関数詳細 \sf function_name -- 関数のソースコード表示

出力制御とフォーマット

-- 出力形式変更 \x -- 拡張表示切り替え \x on -- 拡張表示ON \x off -- 拡張表示OFF -- ページング制御 \pset pager off -- ページング無効化 \pset pager on -- ページング有効化 -- 出力フォーマット \pset format aligned -- 整列形式 \pset format unaligned -- 非整列形式 \pset format csv -- CSV形式 -- NULL表示設定 \pset null 'NULL'

トラブルシューティング

接続問題の解決

-- 接続数上限確認 SHOW max_connections; SELECT count(*) FROM pg_stat_activity; -- 接続を強制終了 SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE usename = 'problematic_user'; -- デッドロック確認 SELECT blocked_locks.pid AS blocked_pid, blocked_activity.usename AS blocked_user, blocking_locks.pid AS blocking_pid, blocking_activity.usename AS blocking_user, blocked_activity.query AS blocked_statement, blocking_activity.query AS current_statement_in_blocking_process FROM pg_catalog.pg_locks blocked_locks JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid JOIN pg_catalog.pg_locks blocking_locks ON blocking_locks.locktype = blocked_locks.locktype AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid AND blocking_locks.pid != blocked_locks.pid JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid WHERE NOT blocked_locks.GRANTED;

パフォーマンス問題の診断

-- インデックス不足の確認 SELECT schemaname, tablename, seq_scan, seq_tup_read, seq_tup_read / seq_scan AS avg_tup_read FROM pg_stat_user_tables WHERE seq_scan > 0 ORDER BY seq_tup_read DESC; -- 統計情報の更新 ANALYZE; ANALYZE table_name; -- VACUUM実行状況確認 SELECT schemaname, tablename, last_vacuum, last_autovacuum, n_dead_tup FROM pg_stat_user_tables WHERE n_dead_tup > 1000; -- 手動VACUUM実行 VACUUM table_name; VACUUM ANALYZE table_name; VACUUM FULL table_name; -- 注意:ロックが発生

ログ分析

-- エラーログ確認(設定により場所が異なる) SHOW log_directory; SHOW log_filename; -- pg_logのサンプルクエリ(csvログ形式の場合) -- ログファイルを直接確認する必要があります -- 現在の設定確認 SHOW logging_collector; SHOW log_statement; SHOW log_min_duration_statement;

データ整合性チェック

-- テーブルの整合性チェック SELECT * FROM pg_stat_user_tables WHERE n_dead_tup > n_live_tup; -- 外部キー制約チェック SELECT conname, conrelid::regclass, confrelid::regclass FROM pg_constraint WHERE contype = 'f' AND NOT EXISTS ( SELECT 1 FROM pg_trigger WHERE tgconstraint = pg_constraint.oid ); -- 重複データチェック SELECT column_name, count(*) FROM table_name GROUP BY column_name HAVING count(*) > 1;

開発現場でよくあるワンライナー

データ調査系

-- テーブル行数カウント(全テーブル) SELECT schemaname, tablename, n_live_tup AS row_count FROM pg_stat_user_tables ORDER BY n_live_tup DESC; -- カラム一覧取得(情報スキーマ使用) SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE table_name = 'users'; -- 最近作成されたテーブル一覧 SELECT tablename, tableowner FROM pg_tables WHERE schemaname = 'public' ORDER BY tablename; -- NULL値の多いカラム特定 SELECT column_name, (SELECT count(*) FROM table_name WHERE column_name IS NULL) as null_count, (SELECT count(*) FROM table_name) as total_count FROM information_schema.columns WHERE table_name = 'your_table';

データメンテナンス系

-- 重複データ削除(最新を残す) DELETE FROM table_name a USING ( SELECT MIN(ctid) as ctid, column_name FROM table_name GROUP BY column_name HAVING COUNT(*) > 1 ) b WHERE a.column_name = b.column_name AND a.ctid <> b.ctid; -- ランダムサンプルデータ取得 SELECT * FROM users TABLESAMPLE SYSTEM (1); -- 1%サンプリング -- 日付範囲でのデータ集計 SELECT DATE_TRUNC('day', created_at) as day, count(*) FROM orders WHERE created_at >= CURRENT_DATE - INTERVAL '30 days' GROUP BY DATE_TRUNC('day', created_at) ORDER BY day;

システム運用系

ターミナル
# データベースサイズ監視 psql -d database_name -c "SELECT pg_size_pretty(pg_database_size('database_name'));" # テーブルサイズTOP10 psql -d database_name -c " SELECT tablename, pg_size_pretty(pg_total_relation_size(tablename::regclass)) AS size FROM pg_tables WHERE schemaname = 'public' ORDER BY pg_total_relation_size(tablename::regclass) DESC LIMIT 10;" # 接続数監視 psql -d database_name -c "SELECT count(*), usename FROM pg_stat_activity GROUP BY usename;"

開発効率化

-- 開発用データリセット(危険:注意して使用) TRUNCATE TABLE orders RESTART IDENTITY CASCADE; -- 外部キー制約を一時無効化 SET session_replication_role = replica; -- データ操作 SET session_replication_role = DEFAULT; -- トランザクション内での安全なテスト BEGIN; -- テスト用の操作 SELECT * FROM users WHERE test_condition; ROLLBACK; -- 変更を破棄

JSON操作(PostgreSQL 9.3+)

-- JSONデータの抽出 SELECT data->>'name' as name FROM json_table WHERE data ? 'name'; -- JSON配列の操作 SELECT jsonb_array_elements(data->'items') FROM json_table; -- JSON値での検索 SELECT * FROM json_table WHERE data @> '{"status": "active"}';

まとめ

PostgreSQL CLIコマンドは開発現場で毎日使用するツールです。本チートシートで紹介したコマンドを活用することで、データベース操作が格段に効率化されます。

重要なポイント:

  • 本番環境では必ずバックアップを取ってから操作する
  • 権限管理は最小権限の原則に従う
  • パフォーマンス監視は定期的に実施する
  • メタコマンドを活用して作業効率を向上させる

開発現場では、基本的なCRUD操作から高度なパフォーマンスチューニングまで幅広い知識が求められます。このチートシートを手元に置いて、PostgreSQLを使った開発をより効率的に進めてください。

継続的な学習として、PostgreSQL公式ドキュメントや\hコマンドでのヘルプ機能も積極的に活用することをお勧めします。

この記事はいかがでしたか?

もしこの記事が参考になりましたら、
高評価をいただけると大変嬉しいです!

--

皆様からの応援が励みになります。ありがとうございます! ✨