SQL: データ操作とデータ型の要点
内容の確認日: 2026-10-29
この分野は出題範囲の S3.1 (SQL コマンド) のうち、SELECT・INSERT・UPDATE・DELETE とデータ型を扱います。S3.1 は 50 問中およそ 13 問と、出題数が最も多い中分類です (テーブル定義などの残りは「SQL: テーブル定義とデータベースオブジェクト」で扱います)。
SQL の問題は「実行したときの出力」を問う形が多く、NULL の扱いや型の変換など、細かい挙動の知識が問われます。この記事のコード例はすべて PostgreSQL 14 で実行した結果です。出力は列を | で区切り、NULL は NULL と表示しています。
SELECT の基本と NULL
PostgreSQL では NULL を「どの値よりも大きい」として並べるので、昇順では最後、降順では最初に来ます。NULLS FIRST・NULLS LAST で変えられます。LIMIT と OFFSET は並べ替えた後に適用されます。
CREATE TABLE emp (name text, dept text, salary integer);INSERT INTO emp VALUES ('a', 'dev', 400), ('b', 'dev', NULL), ('c', 'ops', 300), ('d', 'ops', 500);SELECT name FROM emp ORDER BY salary DESC LIMIT 2;SELECT dept, count(*), count(salary), sum(salary) FROM emp GROUP BY dept ORDER BY dept;SELECT dept FROM emp GROUP BY dept HAVING sum(salary) > 500;psql -A -t -P null=NULL -f example.sql b d dev|2|1|400 ops|2|2|800 ops
count(*) は行の数、count(列) と sum などの集約関数は NULL を除いて計算します。集約した結果で絞り込むのは HAVING で、WHERE に集約関数を書くとエラー (42803) になります。DISTINCT は重複を除き、NULL どうしは同じものとして 1 行にまとめます。
結合と副問い合わせ
JOIN (INNER JOIN) は条件に合う組み合わせだけ、LEFT JOIN は左のテーブルの行をすべて残し、相手がない列を NULL にします。RIGHT JOIN・FULL JOIN・CROSS JOIN (直積) もあります。
副問い合わせの IN・EXISTS は似ていますが、NOT IN は副問い合わせの結果に NULL が含まれると、どの行も選ばれなくなります (x <> NULL が NULL になるため)。NULL がありうるときは NOT EXISTS を使います。
CREATE TABLE a (id integer);CREATE TABLE b (id integer, v text);INSERT INTO a VALUES (1), (2), (3);INSERT INTO b VALUES (2, 'x'), (NULL, 'y');SELECT a.id, b.v FROM a LEFT JOIN b ON a.id = b.id ORDER BY a.id;SELECT count(*) FROM a WHERE id NOT IN (SELECT id FROM b);SELECT count(*) FROM a WHERE NOT EXISTS (SELECT 1 FROM b WHERE b.id = a.id);psql -A -t -P null=NULL -f example.sql 1|NULL 2|x 3|NULL 0 2
集合演算の UNION は重複を除き、UNION ALL は除きません。INTERSECT (共通部分)・EXCEPT (差) もあります。
INSERT・UPDATE・DELETE
INSERT ... SELECT で問い合わせの結果を挿入でき、RETURNING で挿入・更新・削除した行の値を返せます。ON CONFLICT (列) DO NOTHING は一意制約の違反を無視し、DO UPDATE SET ... は既存の行を更新します (EXCLUDED は挿入しようとした行)。UPDATE ... FROM で、ほかのテーブルを結合した条件で更新できます。
CREATE TABLE stock (sku text PRIMARY KEY, qty integer);INSERT INTO stock VALUES ('A', 5) RETURNING qty;INSERT INTO stock VALUES ('A', 3) ON CONFLICT (sku) DO UPDATE SET qty = stock.qty + EXCLUDED.qty;UPDATE stock SET qty = qty * 2 RETURNING sku, qty;psql -A -t -P null=NULL -f example.sql 5 A|16
UPDATE・DELETE に WHERE を書かないと、すべての行が対象になります。
数値・文字列・論理値の型
・整数: smallint・integer・bigint。整数どうしの割り算は小数点以下を切り捨てる
・numeric(全体の桁数, 小数点以下の桁数) (decimal も同じ): 誤差のない 10 進数。桁を超える小数は四捨五入、整数部分が入らなければエラー
・real・double precision: 浮動小数点数 (誤差がある)
・varchar(n): n 文字を超えるとエラー (明示的な型変換なら切り詰め)。char(n): 空白で埋めるが、末尾の空白は意味を持たない。text: 長さの上限なし
・boolean: true・yes・on・1 などを受け付け、psql では t・f と表示される
SELECT 7 / 2, 7 / 2.0, 123.456::numeric(5,2), 2.5::numeric::integer;SELECT char_length('ab'::char(5)), 'abcd'::varchar(3), 'yes'::boolean;psql -A -t -P null=NULL -f example.sql 3|3.5000000000000000|123.46|3 2|abc|t
日付と時刻・JSON・自動採番
date に整数を足すと日数だけ進み、date どうしの引き算は日数の整数です。timestamp どうしの引き算は interval で、interval '1 month' を足すと月末を超える日はその月の末日になります。
SELECT date '2026-01-31' + 1, date '2026-03-01' - date '2026-02-01';SELECT timestamp '2026-01-31 10:00' + interval '1 month', timestamp '2026-01-02 03:00' - timestamp '2026-01-01 01:30';psql -A -t -P null=NULL -f example.sql 2026-02-01|28 2026-02-28 10:00:00|1 day 01:30:00
json は入力した文字列をそのまま保存し、jsonb は解析してバイナリで保存します (重複したキーは最後の値だけ残り、キーは並べ替えられる)。-> は jsonb のまま、->> は text で取り出し、#>> はパスで取り出します。JSON パス (jsonb_path_query など) では、$.items[*] ? (@.p > 150) のように条件で絞り込めます。
SELECT '{"b":1,"a":2,"a":3}'::jsonb;SELECT '{"user": {"name": "alice"}}'::jsonb -> 'user' ->> 'name';psql -A -t -P null=NULL -f example.sql {"a": 3, "b": 1} alice
自動で番号を振る列は serial (integer の列・シーケンス・既定値の組) か、SQL 標準の GENERATED ... AS IDENTITY で作ります。GENERATED ALWAYS の列に値を指定するとエラー (428C9) になり、GENERATED BY DEFAULT なら指定した値が使われます。serial の列に値を直接指定してもシーケンスは進まないので、後で番号が重複することがあります。
試験でよくある引っかけ
降順では
NULLが先頭ORDER BY 列 DESCではNULLが最初に来ます。NULLS LASTで後ろにできます。count(*)とcount(列)count(列)はNULLを数えません。sum・avgもNULLを無視します。NOT INとNULL副問い合わせに
NULLがあると、NOT INは 1 行も選びません。NOT EXISTSを使います。整数の割り算
7 / 2は 3 です。小数の結果がほしいときは、どちらかをnumericにします。varchar(n)を超える値列への挿入はエラー、
::varchar(n)の型変換は切り詰めです。ON CONFLICT DO NOTHINGのRETURNING挿入されなかった行については、何も返しません。
jsonとjsonbjsonbは重複したキーを最後の値だけにし、キーの順番も変わります。
問題で確認する
この分野の問題を、解説つきで読めます (登録不要)。
出典・参考
- LPI-Japan「OSS-DB Silver」(出題範囲)
- PostgreSQL 14 文書「SELECT」
- PostgreSQL 14 文書「INSERT」
- PostgreSQL 14 文書「データ型」
- PostgreSQL 14 文書「JSON 関数と演算子」
コード例は、PostgreSQL 14 で実際に実行して結果を確認しています。