6. PostgreSQL SQLチートシート¶
6.1. 基本のSELECT文¶
6.1.1. 基本構文¶
-- 全カラムを選択
SELECT * FROM テーブル名;
-- 特定のカラムを選択
SELECT カラム1, カラム2 FROM テーブル名;
-- カラムに別名を付ける
SELECT カラム1 AS "別名1", カラム2 AS "別名2" FROM テーブル名;
-- 重複を除外
SELECT DISTINCT カラム名 FROM テーブル名;
6.2. WHERE句(条件指定)¶
6.2.1. 比較演算子¶
-- 等しい
SELECT * FROM students WHERE grade = 1;
-- 等しくない
SELECT * FROM students WHERE grade != 1;
SELECT * FROM students WHERE grade <> 1;
-- より大きい、以上
SELECT * FROM scores WHERE score > 80;
SELECT * FROM scores WHERE score >= 80;
-- より小さい、以下
SELECT * FROM scores WHERE score < 60;
SELECT * FROM scores WHERE score <= 60;
-- 範囲指定
SELECT * FROM scores WHERE score BETWEEN 60 AND 80;
-- リストに含まれる
SELECT * FROM students WHERE grade IN (1, 2);
-- NULLの判定
SELECT * FROM students WHERE remarks IS NULL;
SELECT * FROM students WHERE remarks IS NOT NULL;
6.2.2. 文字列の検索(PostgreSQL)¶
-- 部分一致(%は任意の0文字以上)
SELECT * FROM students WHERE last_name LIKE '田中%';
SELECT * FROM students WHERE first_name LIKE '%子';
SELECT * FROM students WHERE last_name LIKE '%田%';
-- 文字数指定(_は任意の1文字)
SELECT * FROM students WHERE last_name LIKE '田_';
-- 大文字小文字を区別しない(ILIKE)
SELECT * FROM students WHERE last_name ILIKE 'tanaka%';
-- 正規表現(~演算子)
SELECT * FROM students WHERE last_name ~ '^田中'; -- 田中で始まる
SELECT * FROM students WHERE first_name ~ '子$'; -- 子で終わる
6.2.3. 複数条件の組み合わせ¶
-- AND(両方満たす)
SELECT * FROM students s
INNER JOIN classes c ON s.class_id = c.class_id
WHERE c.grade = 1 AND c.class_name = '1年1組';
-- OR(どちらか満たす)
SELECT * FROM students WHERE grade = 1 OR grade = 2;
-- NOT(条件を満たさない)
SELECT * FROM students WHERE NOT grade = 3;
-- 複雑な条件(括弧で優先順位を明確に)
SELECT * FROM students s
INNER JOIN classes c ON s.class_id = c.class_id
WHERE (c.grade = 1 OR c.grade = 2) AND c.class_name LIKE '%1組';
6.3. ORDER BY(並び替え)¶
-- 昇順(小→大、デフォルト)
SELECT * FROM students ORDER BY student_number;
SELECT * FROM students ORDER BY student_number ASC;
-- 降順(大→小)
SELECT * FROM scores ORDER BY score DESC;
-- 複数キーでの並び替え
SELECT s.*, c.grade, c.class_name FROM students s
INNER JOIN classes c ON s.class_id = c.class_id
ORDER BY c.grade ASC, c.class_name ASC, s.student_number ASC;
-- NULLの扱い(PostgreSQL固有)
SELECT * FROM students
ORDER BY remarks NULLS FIRST; -- NULLを先頭に
SELECT * FROM students
ORDER BY remarks NULLS LAST; -- NULLを末尾に(デフォルト)
6.4. LIMIT/OFFSET(件数制限)¶
-- 最初の10件
SELECT * FROM students LIMIT 10;
-- 11件目から10件
SELECT * FROM students LIMIT 10 OFFSET 10;
-- 成績上位5名
SELECT * FROM scores
ORDER BY score DESC
LIMIT 5;
6.5. 集計関数¶
6.5.1. 基本的な集計関数¶
-- 件数
SELECT COUNT(*) FROM students;
SELECT COUNT(student_id) FROM students;
SELECT COUNT(DISTINCT grade) FROM students;
-- 合計
SELECT SUM(score) FROM scores;
-- 平均
SELECT AVG(score) FROM scores;
SELECT ROUND(AVG(score)::numeric, 1) FROM scores; -- 小数点第1位で四捨五入
-- 最大値・最小値
SELECT MAX(score) FROM scores;
SELECT MIN(score) FROM scores;
6.5.2. PostgreSQL固有の集計関数¶
-- 文字列の集約
SELECT string_agg(last_name || ' ' || first_name, ', ' ORDER BY student_number)
FROM students s
INNER JOIN classes c ON s.class_id = c.class_id
WHERE c.grade = 1;
-- 配列への集約
SELECT array_agg(score ORDER BY score DESC)
FROM scores WHERE student_id = 1;
-- 標準偏差・分散
SELECT
STDDEV(score) as "standard_deviation",
VARIANCE(score) as "variance"
FROM scores;
6.6. GROUP BY(グループ化)¶
-- 学年別の生徒数
SELECT grade, COUNT(*) as "student_count"
FROM students
GROUP BY grade;
-- 教科別の平均点
SELECT subject_id, AVG(score) as "avg_score"
FROM scores
GROUP BY subject_id;
-- 複数カラムでグループ化
SELECT c.grade, c.class_name, COUNT(*) as "student_count"
FROM students s
INNER JOIN classes c ON s.class_id = c.class_id
GROUP BY c.class_id, c.grade, c.class_name
ORDER BY c.grade, c.class_name;
-- 集計結果に別名を付ける
SELECT
s.subject_name,
COUNT(*) as "test_count",
AVG(sc.score) as "avg_score",
MAX(sc.score) as "max_score",
MIN(sc.score) as "min_score"
FROM scores sc
JOIN subjects s ON sc.subject_id = s.subject_id
GROUP BY s.subject_id, s.subject_name;
6.7. HAVING(集計結果の絞り込み)¶
-- 平均点が70点以上の教科
SELECT subject_id, AVG(score) as "avg_score"
FROM scores
GROUP BY subject_id
HAVING AVG(score) >= 70;
-- 生徒数が30人以上の学年
SELECT grade, COUNT(*) as "student_count"
FROM students
GROUP BY grade
HAVING COUNT(*) >= 30;
-- WHEREとHAVINGの組み合わせ
SELECT
student_id,
AVG(score) as "avg_score"
FROM scores
WHERE test_id IN (1, 2, 3) -- 最初の3回のテストのみ
GROUP BY student_id
HAVING AVG(score) >= 80 -- 平均80点以上
ORDER BY avg_score DESC;
6.8. PostgreSQL便利な関数¶
6.8.1. 文字列関数¶
-- 文字列結合(||演算子)
SELECT c.grade || '年' || c.class_number || '組' as "class_name" FROM classes c;
SELECT last_name || ' ' || first_name as "full_name" FROM students;
-- CONCAT関数
SELECT CONCAT(c.grade, '年', c.class_number, '組') as "class_name" FROM classes c;
SELECT CONCAT(last_name, ' ', first_name) as "full_name" FROM students;
-- 文字列の長さ(日本語対応)
SELECT last_name, LENGTH(last_name) as "byte_length" FROM students;
SELECT last_name, CHAR_LENGTH(last_name) as "char_length" FROM students;
-- 大文字・小文字変換
SELECT UPPER(class_name), LOWER(class_name) FROM classes;
-- 文字列の切り出し
SELECT SUBSTRING(last_name FROM 1 FOR 1) as "first_char" FROM students;
SELECT LEFT(last_name, 1) as "first_char" FROM students;
SELECT RIGHT(first_name, 1) as "last_char" FROM students;
-- 空白の除去
SELECT TRIM(last_name) FROM students;
SELECT LTRIM(last_name), RTRIM(last_name) FROM students;
-- 文字列の置換
SELECT REPLACE(last_name, '田', '山') FROM students;
-- 文字列の分割
SELECT SPLIT_PART('2025-01-24', '-', 1) as "year";
6.8.2. 数値関数¶
-- 四捨五入
SELECT ROUND(95.456, 2); -- 95.46
SELECT ROUND(95.456); -- 95
-- 切り上げ・切り捨て
SELECT CEIL(95.1), FLOOR(95.9);
SELECT CEILING(95.1); -- CEILと同じ
-- 切り捨て(小数点以下の桁数指定)
SELECT TRUNC(95.456, 2); -- 95.45
-- 絶対値
SELECT ABS(score - 70) as "diff_from_70" FROM scores;
-- べき乗・平方根
SELECT POWER(2, 10); -- 2の10乗
SELECT SQRT(16); -- 4
-- 剰余
SELECT MOD(10, 3); -- 1
SELECT 10 % 3; -- 1(演算子)
6.8.3. 日付・時刻関数¶
-- 現在の日時(PostgreSQL)
SELECT CURRENT_DATE; -- 日付のみ
SELECT CURRENT_TIME; -- 時刻のみ
SELECT CURRENT_TIMESTAMP; -- 日時
SELECT NOW(); -- 日時(CURRENT_TIMESTAMPと同じ)
-- 日付の一部を取得
SELECT
EXTRACT(YEAR FROM test_date) as "year",
EXTRACT(MONTH FROM test_date) as "month",
EXTRACT(DAY FROM test_date) as "day",
EXTRACT(DOW FROM test_date) as "day_of_week" -- 0=日曜
FROM tests;
-- DATE_PART関数(EXTRACTと同じ)
SELECT DATE_PART('year', test_date) FROM tests;
-- 日付の計算
SELECT test_date + INTERVAL '7 days' FROM tests;
SELECT test_date - INTERVAL '1 month' FROM tests;
SELECT test_date + INTERVAL '1 year 2 months 3 days';
-- 日付の差分
SELECT AGE(CURRENT_DATE, '2000-01-01'); -- 期間を返す
SELECT CURRENT_DATE - '2000-01-01'; -- 日数を返す
-- 日付のフォーマット
SELECT TO_CHAR(test_date, 'YYYY年MM月DD日') FROM tests;
SELECT TO_CHAR(test_date, 'YYYY-MM-DD HH24:MI:SS');
6.8.4. 型変換(キャスト)¶
-- CAST関数
SELECT CAST('123' AS INTEGER);
SELECT CAST(123 AS TEXT);
SELECT CAST('2025-01-24' AS DATE);
-- ::演算子(PostgreSQL固有)
SELECT '123'::INTEGER;
SELECT 123::TEXT;
SELECT '2025-01-24'::DATE;
-- 数値の精度変換
SELECT CAST(123.456 AS NUMERIC(5,2)); -- 123.46
SELECT 123.456::NUMERIC(5,2);
6.9. 条件分岐¶
6.9.1. CASE式¶
-- 成績の評価
SELECT
student_id,
score,
CASE
WHEN score >= 90 THEN '優'
WHEN score >= 80 THEN '良'
WHEN score >= 70 THEN '可'
ELSE '不可'
END as "evaluation"
FROM scores;
-- 学年の表示
SELECT
last_name || ' ' || first_name as "name",
CASE c.grade
WHEN 1 THEN '1年生'
WHEN 2 THEN '2年生'
WHEN 3 THEN '3年生'
END as "grade_name"
FROM students s
INNER JOIN classes c ON s.class_id = c.class_id;
6.9.2. COALESCE(NULL対応)¶
-- NULLの場合にデフォルト値を使用
SELECT
last_name || ' ' || first_name as "name",
COALESCE(s.student_number, '番号未設定') as "student_number"
FROM students s;
-- 複数の値から最初の非NULL値を取得
SELECT COALESCE(gender, '未設定') FROM students;
6.9.3. NULLIF¶
-- 特定の値をNULLに変換
SELECT NULLIF(score, 0) FROM scores; -- 0点をNULLに
-- ゼロ除算の回避
SELECT total / NULLIF(count, 0) as "average";
6.10. ウィンドウ関数(PostgreSQL)¶
6.10.1. ランキング関数¶
-- 順位付け(同じ値は同じ順位、次の順位は飛ぶ)
SELECT
student_id,
score,
RANK() OVER (ORDER BY score DESC) as "rank"
FROM scores;
-- 順位付け(同じ値は同じ順位、次の順位は連続)
SELECT
student_id,
score,
DENSE_RANK() OVER (ORDER BY score DESC) as "dense_rank"
FROM scores;
-- 連番(同じ値でも連番)
SELECT
student_id,
score,
ROW_NUMBER() OVER (ORDER BY score DESC) as "row_num"
FROM scores;
-- パーセンタイル順位
SELECT
student_id,
score,
PERCENT_RANK() OVER (ORDER BY score) as "percent_rank"
FROM scores;
6.10.2. グループ内での順位¶
-- 教科別の順位
SELECT
student_id,
subject_id,
score,
RANK() OVER (PARTITION BY subject_id ORDER BY score DESC) as "subject_rank"
FROM scores;
-- 学年・クラス別の成績順位
SELECT
st.last_name || ' ' || st.first_name as "name",
c.grade,
c.class_name,
AVG(sc.score) as "avg_score",
RANK() OVER (
PARTITION BY c.grade, c.class_name
ORDER BY AVG(sc.score) DESC
) as "class_rank"
FROM students st
JOIN scores sc ON st.student_id = sc.student_id
JOIN classes c ON st.class_id = c.class_id
GROUP BY st.student_id, st.last_name, st.first_name, c.grade, c.class_name;
6.10.3. 移動集計¶
-- 累積合計
SELECT
test_date,
score,
SUM(score) OVER (ORDER BY test_date) as "cumulative_score"
FROM scores
WHERE student_id = 1;
-- 移動平均(前後1行を含む3行の平均)
SELECT
test_date,
score,
AVG(score) OVER (
ORDER BY test_date
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
) as "moving_avg"
FROM scores;
-- 直前の値を取得
SELECT
test_date,
score,
LAG(score, 1) OVER (ORDER BY test_date) as "prev_score",
score - LAG(score, 1) OVER (ORDER BY test_date) as "diff"
FROM scores;
6.11. クエリの組み合わせ¶
6.11.1. サブクエリ¶
-- 平均点以上の生徒
SELECT * FROM scores
WHERE score > (SELECT AVG(score) FROM scores);
-- 各教科の最高得点者
SELECT * FROM scores s1
WHERE score = (
SELECT MAX(score)
FROM scores s2
WHERE s1.subject_id = s2.subject_id
);
-- EXISTS(存在確認)
SELECT * FROM students s
WHERE EXISTS (
SELECT 1 FROM scores sc
WHERE sc.student_id = s.student_id
AND sc.score >= 90
);
6.11.2. WITH句(共通テーブル式)¶
-- 各生徒の平均点を計算してから使用
WITH student_averages AS (
SELECT
student_id,
AVG(score) as "avg_score"
FROM scores
GROUP BY student_id
)
SELECT
s.last_name || ' ' || s.first_name as "name",
sa.avg_score
FROM students s
JOIN student_averages sa ON s.student_id = sa.student_id
WHERE sa.avg_score >= 80
ORDER BY sa.avg_score DESC;
-- 複数のCTE
WITH
high_scores AS (
SELECT student_id, subject_id, score
FROM scores
WHERE score >= 80
),
student_counts AS (
SELECT student_id, COUNT(*) as "high_score_count"
FROM high_scores
GROUP BY student_id
)
SELECT
s.last_name || ' ' || s.first_name as "name",
sc.high_score_count
FROM students s
JOIN student_counts sc ON s.student_id = sc.student_id
WHERE sc.high_score_count >= 3;
6.11.3. UNION/INTERSECT/EXCEPT¶
-- 結果の結合(重複除去)
SELECT last_name || ' ' || first_name as "name" FROM students s
INNER JOIN classes c ON s.class_id = c.class_id
WHERE c.grade = 1
UNION
SELECT last_name || ' ' || first_name as "name" FROM students s
INNER JOIN classes c ON s.class_id = c.class_id
WHERE c.class_name = '1年1組';
-- 結果の結合(重複含む)
SELECT last_name || ' ' || first_name as "name" FROM students s
INNER JOIN classes c ON s.class_id = c.class_id
WHERE c.grade = 1
UNION ALL
SELECT last_name || ' ' || first_name as "name" FROM students s
INNER JOIN classes c ON s.class_id = c.class_id
WHERE c.class_name = '1年1組';
-- 共通部分
SELECT student_id FROM scores WHERE subject_id = 1 AND score >= 80
INTERSECT
SELECT student_id FROM scores WHERE subject_id = 2 AND score >= 80;
-- 差分
SELECT student_id FROM students
EXCEPT
SELECT DISTINCT student_id FROM scores;