🔖 キーワード索引
「主キー 」を取り巻く中核キーワード群です。 検索やインデックス作成で参照する際の手がかりにしてください。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になります。
主キー Primary Key 一意性 NOT NULL 代理キー 複合キー 外部キー インデックス
💡 30秒で分かる結論 — 主キー
🍰 まずはやさしく
主キーはデータの背番号のようなものです。
データを迷わず見つけるために使います。
スマホの連絡先にある個別のIDが例です。
まずは主キーの結論をまとめます。
最も忙しい読者のために、 まず結論だけまとめます。 詳細は以下のセクションへ:
主キー(Primary Key) =テーブル内で 各行を一意に識別 する列(または列の組合せ)。条件:(1) 一意 、 (2) NULL 不可 、 (3) 不変 (できれば)。 自然キー (マイナンバー等の実在 ID)vs 代理キー (システム生成の連番/UUID)。 代理キー推奨。主キー=自動的に B-Tree インデックス が作られ高速検索可能。 外部キー と組み合わせて参照整合性を保つ。 リレーショナル DB の根幹。
📍 文脈 — どこで出会うか
🍰 まずはやさしく
主キーはデータの間違いを防ぐ番人です。
同じデータが混ざるのを防ぐために使います。
部活の名簿で名前が重なる時に役立ちます。
主キーをどこで使うのかを説明します。
「同じユーザーの行が 3 行ある」 「ID が NULL」 — どちらもデータが壊れているサイン。 主キーがちゃんと定義されていれば、 DB が自動で防いでくれます。
このページの読み方 :まず 30秒結論 と 直感 を読み、 必要に応じて 数式 や 計算例 、 落とし穴 に進んでください。
🎨 直感で掴む
🍰 まずはやさしく
主キーは世界に一つだけの印です。
誰と誰かを正しく区別するために使います。
出席簿の学籍番号がちょうどこの例です。
主キーを選ぶコツを直感的に学びます。
クラスの出席簿に喩えると:
名前(山田太郎)=同姓同名の可能性あり → 不適
学籍番号(2024001)=必ず一意 → 適切な主キー
主キーは「絶対に重複しない 」 「必ず値がある 」 「後から変わらない 」 ものを選ぶのが鉄則。
🎨 SSDSE-B-2026 の主キー構造
SSDSE-B-2026 の各レコードは「年 × 都道府県」で一意に決まる。 つまり (SSDSE 年, Code, Prefecture) の組合せが「複合主キー」になっている。 単独の Code 列 (R01000 = 北海道, R13000 = 東京都, ...) は 都道府県表のみ では主キーだが、 SSDSE-B-2026 では 12 年分 × 47 県 = 564 行あるため Code 単独では重複する。
候補 一意? 理由
Prefecture (都道府県名) 否 "東京都" は 2012 年・2013 年・...・2023 年で 12 回出現
Code (R01000 など) 否 同上。 年方向に重複
(SSDSE 年, Code) 是 複合主キー 。 12 年 × 47 県 = 564 行すべて一意
(SSDSE 年, Prefecture) 是 同等に主キーとして機能 (Code と Prefecture は 1:1 対応)
これを SQL で表現するなら PRIMARY KEY (year, code)。 pandas なら df.set_index(['SSDSE', 'Code'])。 主キーが定義されていれば、 重複削除も「年次集計のための GROUP BY」も「他テーブルとの JOIN」も安全に行える 。 例えば、 同じ複合主キーを持つ別表 (A1101 だけの抜粋 vs A1303 だけの抜粋) を merge(on=['SSDSE','Code']) で結合すれば、 行ズレなく統合できる。
✅ 理解度チェック
主キーが満たすべき 3 条件(一意性・非 NULL・不変性)を説明できるか。
自然キーと代理キー(サロゲートキー)の違いと使い分けを 1 例で挙げられるか。
複合主キーが必要になる典型シナリオ(売上明細など)を 1 つ示せるか。
主キーと一意制約・インデックスの関係を区別できるか。
🔬 数式を言葉で読み解く
🔬 概念を言葉で読み解く(詳細版)
主キー(Primary Key, PK) は、 リレーショナルデータベースのテーブルの「各行を一意に識別する属性または属性の組 」。 SSDSE-B-2026.csv の場合、 (年度, 地域コード) の複合主キーが各レコードを一意に決めます。 PK は単なる「行番号」ではなく、 NULL 不可・一意性保証・自動インデックスといった3 つの絶対要件 を満たします。
① 主キーの形式的定義
② 候補キー・代理キー・自然キー
キーの種類 定義 SSDSE-B-2026 での例
スーパーキー 一意性を持つ属性集合(最小性は不問) (年度, 地域コード, 都道府県)
候補キー 最小性を満たすスーパーキー (年度, 地域コード), (年度, 都道府県)
主キー(PK) 候補キーから 1 つ選んだもの (年度, 地域コード)
代替キー PK 以外の候補キー (年度, 都道府県)
自然キー 業務上の意味を持つキー (年度, 地域コード)、 マイナンバー、 ISBN
代理キー(surrogate key) 人工的な ID(AUTO_INCREMENT) SSDSE-B には標準で含まれない、 必要なら追加
③ SSDSE-B-2026 の主キー設計
SSDSE-B-2026 は 47 都道府県 × 12 年(2012-2023) = 564 行 。 主キー候補:
(年度, 地域コード) :47 × 12 = 564、 一意。 ✅ 推奨
(年度, 都道府県):47 × 12 = 564、 一意だが文字列で重い
地域コード単独:47 種類しかないので 12 年分で重複 → NG
年度単独:13 種類しかないので NG
地域コード(例:R13000=東京都)は ISO 3166-2:JP 規格に対応し、 国際標準との互換性も高い。 これが「(年度, 地域コード)」を主キーに選ぶ実務的根拠。
④ B-tree インデックスとパフォーマンス
SSDSE-B-2026 を SQLite で主キー付きロード
SSDSE-B-2026 を SQLite にロードする際、 (年度, 地域コード) を主キーに指定することで、 「2023 年の東京都を取得」というクエリが O(log n) に高速化。 564 行では体感差は小さいが、 主キー設計の練習として最適。 また主キーがあれば INSERT OR REPLACE で冪等更新も可能。
🏭 産業界での活用事例(6 件)
業界 事例 主キーの選び方 SSDSE-B-2026 との対比
銀行 口座管理 口座番号(10 桁) 口座 = レコード単位、 SSDSE-B では (年度, 地域コード)
EC 注文管理 注文 ID(UUID または AUTO_INCREMENT) SSDSE-B も人工キー追加可能
医療 電子カルテ 患者 ID(自治体ベース ID) マイナンバーは外部 PK 候補
政府 マイナンバー DB マイナンバー 12 桁 個人レベルの一意識別子
SaaS マルチテナント DB (テナント ID, レコード ID) 複合 PK SSDSE-B の (年度, 地域) と類似
分析基盤 BigQuery / Snowflake PK 制約なし、 ロジカル PK SSDSE-B BigQuery 取込でも同様
⚖️ 主キー設計の比較表
方式 例 長所 短所
自然キー(複合) (年度, 地域コード) 業務意味あり、 外部システムと連携易 変更困難、 JOIN コスト
自然キー(単独) マイナンバー、 ISBN シンプル 業務変更で揺らぐ
代理キー(連番) AUTO_INCREMENT id シンプル・高速・JOIN 軽量 意味なし、 シャーディング困難
代理キー(UUID) '550e8400-e29b-41d4-a716-...' 分散システム可、 衝突しない 16 byte で重い、 インデックス局所性低
ULID / Snowflake ID 時系列順 UUID UUID 利点 + 局所性改善 導入コスト
ハッシュキー SHA-256 of natural key 長さ固定 業務トレース困難
💥 失敗例から学ぶ
💥 主キーに NULL を許す
「都道府県 単独で PK」だと未登録が発生し NULL 混入、 一意性破綻。 NOT NULL を必ず指定。
💥 PK を後から変更
PK は外部キー(FK)で参照される。 変更すると参照側も書き換え必要。 SSDSE-B では「年度 4 桁 → 6 桁」化など。
💥 PK に意味付け
「東京都の id は必ず 1 番」という決め打ちは将来の拡張で破綻。 代理キーは「意味なし」が原則。
💥 UUID 主キーで INSERT 性能低下
B-tree インデックスはランダム UUID で局所性が悪化、 INSERT が 5〜10 倍遅くなることも。 ULID や Snowflake ID を選ぶ。
💥 重複データの PK 衝突
SSDSE-B-2026 を 2 回ロードすると UNIQUE constraint failed。 INSERT OR REPLACE や ON CONFLICT 句で対応。
📝 演習問題(5 問・解答付き)
問題: SSDSE-B-2026 を SQLite にロードし、 (年度, 地域コード) を主キーに指定せよ。
▼ 解答
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 SSDSE-B-2026(年度) Prefecture(都道府県) A1101(総人口)
北海道 2,023 北海道 5,092,000
東京都 2,023 東京都 14,086,000
沖縄県 2,023 沖縄県 1,468,000
…(全 47 行)
📋 コピー import sqlite3 , pandas as pd
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = 1 ) # 日本語の列名で読む(2 行目を見出しにする)
conn = sqlite3 . connect ( ':memory:' )
conn . execute ( '''CREATE TABLE ssdse_b (
年度 INTEGER, 地域コード TEXT, 都道府県 TEXT, 総人口 INTEGER,
PRIMARY KEY (年度, 地域コード))''' )
df [[ '年度' , '地域コード' , '都道府県' , '総人口' ]] . to_sql ( 'ssdse_b' , conn , if_exists = 'append' , index = False )
print ( conn . execute ( "SELECT COUNT(*) FROM ssdse_b" ) . fetchone ()) # (564,)
問題: SSDSE-B-2026 で「都道府県」を単独 PK にしようとするとなぜ失敗する?
▼ 解答
47 都道府県 × 12 年 = 564 行。 都道府県名は 12 回ずつ重複するため一意性違反。 (年度, 都道府県) の複合キーが必要。
問題: (年度, 地域コード) と (年度, 都道府県) のどちらを PK にするか、 理由とともに述べよ。
▼ 解答
(年度, 地域コード) を推奨。 理由:(1) コードは ISO 標準で外部連携に有利、 (2) 整数/短文字列でインデックスが軽量、 (3) 都道府県名は表記揺れリスク(東京都 vs 東京)。
問題: SSDSE-B-2026 の主キーに重複値を INSERT したらどうなるか、 また対策は?
▼ 解答
UNIQUE constraint failed エラー。 対策:(1) INSERT OR IGNORE(既存を無視)、 (2) INSERT OR REPLACE(上書き)、 (3) ON CONFLICT (年度, 地域コード) DO UPDATE(PostgreSQL 互換)。
問題: SSDSE-B-2026 から「都道府県マスタ」と「統計事実テーブル」に正規化する場合、 それぞれの PK は?
▼ 解答
都道府県マスタ:PK = 地域コード(47 行、 例 R13000=東京都)。 統計事実テーブル:PK = (年度, 地域コード)、 FK = 地域コード → 都道府県マスタ。 これで 3NF を満たす。
📖 関連用語辞典(10 語)
主キー(PK) 行を一意に識別する属性集合。 NULL 不可、 一意。
外部キー(FK) 他表の PK を参照する属性。 参照整合性を保証。
候補キー 最小性を満たすスーパーキー。 PK の選択肢。
代理キー(surrogate) 人工的に振った ID(AUTO_INCREMENT)。 業務上意味なし。
自然キー(natural) 業務的意味を持つキー(マイナンバー、 ISBN)。
複合キー 2 つ以上の属性の組による PK。 SSDSE-B の (年度, 地域コード) が典型。
参照整合性 FK が参照する PK が必ず存在する状態。
UNIQUE 制約 一意性のみ要求(NULL 可)。 PK の弱い版。
B-tree インデックス PK に自動で張られる検索構造。 計算量 O(log n)。
UUID / ULID 分散システム向けユニーク ID。 UUID は 128 ビット。
🔬 SSDSE-B-2026 で主キー設計の総合実習
実習:3NF 正規化 + FK 整合性 + UPSERT パターンの統合
🎯 やること :SSDSE-B-2026 を「都道府県マスタ」「地方区分マスタ」「統計事実」の 3 テーブルに正規化、 主キーと外部キーで参照整合性を確立、 UPSERT で冪等更新を実装する。
📥 入力 :SSDSE-B-2026.csv 全 564 行。
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 import sqlite3 , pandas as pd
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = 1 )
# 地方区分マッピング
BLOCKS = {
'北海道' : '北海道' ,
'青森県' : '東北' , '岩手県' : '東北' , '宮城県' : '東北' , '秋田県' : '東北' , '山形県' : '東北' , '福島県' : '東北' ,
'茨城県' : '関東' , '栃木県' : '関東' , '群馬県' : '関東' , '埼玉県' : '関東' , '千葉県' : '関東' , '東京都' : '関東' , '神奈川県' : '関東' ,
'新潟県' : '中部' , '富山県' : '中部' , '石川県' : '中部' , '福井県' : '中部' , '山梨県' : '中部' , '長野県' : '中部' , '岐阜県' : '中部' , '静岡県' : '中部' , '愛知県' : '中部' ,
'三重県' : '近畿' , '滋賀県' : '近畿' , '京都府' : '近畿' , '大阪府' : '近畿' , '兵庫県' : '近畿' , '奈良県' : '近畿' , '和歌山県' : '近畿' ,
'鳥取県' : '中国' , '島根県' : '中国' , '岡山県' : '中国' , '広島県' : '中国' , '山口県' : '中国' ,
'徳島県' : '四国' , '香川県' : '四国' , '愛媛県' : '四国' , '高知県' : '四国' ,
'福岡県' : '九州' , '佐賀県' : '九州' , '長崎県' : '九州' , '熊本県' : '九州' , '大分県' : '九州' , '宮崎県' : '九州' , '鹿児島県' : '九州' , '沖縄県' : '九州' ,
}
conn = sqlite3 . connect ( ':memory:' )
conn . execute ( 'PRAGMA foreign_keys = ON' )
# 1. 地方区分マスタ
conn . execute ( '''CREATE TABLE 地方区分 (
名称 TEXT PRIMARY KEY
)''' )
conn . executemany ( 'INSERT INTO 地方区分 VALUES (?)' ,
[( b ,) for b in sorted ( set ( BLOCKS . values ()))])
# 2. 都道府県マスタ
conn . execute ( '''CREATE TABLE 都道府県マスタ (
地域コード TEXT PRIMARY KEY,
都道府県 TEXT NOT NULL UNIQUE,
地方区分 TEXT NOT NULL,
FOREIGN KEY (地方区分) REFERENCES 地方区分(名称)
)''' )
master = df [[ '地域コード' , '都道府県' ]] . drop_duplicates () . copy ()
master [ '地方区分' ] = master [ '都道府県' ] . map ( BLOCKS )
master . to_sql ( '都道府県マスタ' , conn , if_exists = 'append' , index = False )
# 3. 統計事実
conn . execute ( '''CREATE TABLE 統計事実 (
年度 INTEGER NOT NULL,
地域コード TEXT NOT NULL,
総人口 INTEGER,
出生数 INTEGER,
PRIMARY KEY (年度, 地域コード),
FOREIGN KEY (地域コード) REFERENCES 都道府県マスタ(地域コード)
)''' )
df [[ '年度' , '地域コード' , '総人口' , '出生数' ]] . to_sql (
'統計事実' , conn , if_exists = 'append' , index = False )
# 集計クエリ:地方区分別人口(3 表 JOIN)
result = conn . execute ( '''
SELECT 区.名称 AS 地方, COUNT(*) AS 件数, SUM(s.総人口) AS 合計人口
FROM 統計事実 s
JOIN 都道府県マスタ m USING (地域コード)
JOIN 地方区分 区 ON m.地方区分 = 区.名称
WHERE s.年度 = 2023
GROUP BY 区.名称
ORDER BY 合計人口 DESC
''' ) . fetchall ()
print ( f " { '地方' : 4s } { '県数' : >4s } { '合計人口' : >12s } " )
print ( '-' * 30 )
for region , n , total in result :
print ( f " { region : 4s } { n : >4d } { total : >12, } " )
📤 実行結果 :
地方 県数 合計人口
------------------------------
関東 7 43,495,000
近畿 7 22,031,000
中部 9 20,758,000
九州 8 12,914,000
東北 6 8,425,000
中国 5 7,071,000
北海道 1 5,092,000
四国 4 3,594,000
💬 結果の読み方 :3 表構造(地方区分マスタ → 都道府県マスタ → 統計事実)で 3NF を満たし、 FK で参照整合性を保証。 「地方区分・地域コード」が他表に存在しない値の挿入は DB レベルで拒否される。 集計クエリは 3 表 JOIN で実現し、 関東 43.5M(35%)、 近畿 22M、 中部 20.8M と上位 3 ブロックが全国の 70% を占める。 主キーと外部キーの組合せが、 業務要件と性能の両立を可能にする。
📓 「主キー」をさらに深掘り — 実データ実践ノート
🔑 SSDSE-B-2026 の構造を「主キー」視点で再点検
SSDSE-B-2026(独立行政法人統計センター、 CC BY 4.0)は 47 都道府県 × 2012-2023 年 = 564 行 × 112 列の表データです。 「主キー」の観点でこのデータを見ると、 以下のような切り口が現れます:
2023 年都道府県別人口 TOP 5 :東京都 14,086,000 人、 神奈川県 9,229,000 人、 大阪府 8,763,000 人、 愛知県 7,477,000 人、 埼玉県 7,331,000 人
2023 年都道府県別出生数 TOP 5 :東京都 86,348 人、 神奈川県 53,991 人、 大阪府 55,292 人、 愛知県 48,402 人、 埼玉県 42,108 人
合計特殊出生率 TOP 3 :沖縄県 1.60、 宮崎県 1.49、 鳥取県 1.46(2023 年)
全国 2023 年合計 :124,353,000 人、 727,269 人出生、 474,741 件婚姻、 183,814 件離婚
12 年間の変化 :全国総人口は 2012 年 127 百万人台から 2023 年 124.4 百万人台へ。 平均年率 -0.23% の緩やかな減少
🔑 「主キー」をテーマにした SSDSE-B-2026 分析シナリオ(10 件)
# シナリオ 主要な「主キー」要素
1 全 47 都道府県の 2023 年人口を読み込み、 上位 5 県を抽出 一意性・参照整合性・B-tree・複合キー
2 2012→2023 の人口変化率を計算、 増加県・減少県をランキング 一意性・参照整合性・B-tree・複合キー
3 合計特殊出生率と婚姻率の散布図、 相関係数を計算 一意性・参照整合性・B-tree・複合キー
4 気温(最高・最低)と出生率の関係を分析 一意性・参照整合性・B-tree・複合キー
5 地方ブロック(北海道〜九州)単位の集計と分布比較 一意性・参照整合性・B-tree・複合キー
6 年度別全国合計の時系列で移動平均・トレンド推定 一意性・参照整合性・B-tree・複合キー
7 転入超過率(転入÷総人口)の都道府県マップ可視化 一意性・参照整合性・B-tree・複合キー
8 離婚率と婚姻率の比、 都道府県差の要因探索 一意性・参照整合性・B-tree・複合キー
9 k-means で都道府県を 5 群にクラスタリングし特徴抽出 一意性・参照整合性・B-tree・複合キー
10 主成分分析で 112 列を 2 次元に圧縮、 可視化 一意性・参照整合性・B-tree・複合キー
🔑 SSDSE-B-2026 の主要指標一覧(活用しやすい列)
列コード 列名 2023 年範囲 「主キー」との関わり
A1101 総人口 537,000(鳥取)〜 14,086,000(東京) 規模感の基本指標
A4101 出生数 3,739(鳥取)〜 86,348(東京) 未来人口の供給源
A4103 合計特殊出生率 0.99(東京)〜 1.60(沖縄) 少子化政策の核心指標
A9101 婚姻件数 2,049(鳥取)〜 160,732(東京) 家族形成の基盤
A9201 離婚件数 — 家族解体の指標
B4101 年平均気温 11.0(北海道)〜 23.7(沖縄) 気候要因の代表
B4102 最高気温(月平均最高値) 30.9(北海道)〜 35.4(埼玉) 夏の極値
B4103 最低気温(月平均最低値) -7.4(北海道)〜 17.5(沖縄) 冬の極値
E4401 高等学校教員数 — 教育インフラ規模
E7201 専修学校生徒数 — 専門教育の規模
🔑 Python 3 段階分析テンプレート — 「主キー」視点で SSDSE-B-2026
段階 1:データロード + 概要把握
🎯 やること :SSDSE-B-2026 を pandas で読み込み、 列数・行数・型を確認。 「主キー」の議論に必要なメタデータ(CC BY 4.0、 47 都道府県、 12 年分)を出力。
📥 入力 :data/raw/SSDSE-B-2026.csv(CP932 エンコーディング)
📋 コピー import pandas as pd
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = 1 )
print ( f "行数: { len ( df ) : , } / 列数: { len ( df . columns ) : , } " )
print ( f "年度範囲: { df [ '年度' ] . min () } - { df [ '年度' ] . max () } " )
print ( f "都道府県数: { df [ '都道府県' ] . nunique () } " )
print ( f "出典: 独立行政法人統計センター. SSDSE-B-2026 (CC BY 4.0)" )
📤 出力 :
行数: 564 / 列数: 112
年度範囲: 2012-2023
都道府県数: 47
出典: 独立行政法人統計センター. SSDSE-B-2026 (CC BY 4.0)
💬 解説 :564 = 47 × 12 で完全一致=欠損レコードなし。 112 列の指標を「主キー」の文脈で取捨選択していくのが次段階。
段階 2:「主キー」関連列の抽出と統計
🎯 やること :47 都道府県の 2023 年データから、 「主キー」の議論に直結する主要指標を抽出し、 統計値を算出。
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 SSDSE-B-2026(年度) Prefecture(都道府県) A1101(総人口) A4101(出生数) A4103(合計特殊出生率)
北海道 2,023 北海道 5,092,000 24,430 1.06
東京都 2,023 東京都 14,086,000 86,348 0.99
沖縄県 2,023 沖縄県 1,468,000 12,549 1.6
…(全 47 行)
📋 コピー import pandas as pd
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = 1 )
d = df [ df [ '年度' ] == 2023 ]
key_cols = [ '都道府県' , '総人口' , '出生数' , '合計特殊出生率' , '婚姻件数' , '離婚件数' ]
summary = d [ key_cols ] . describe ()
print ( summary . round ( 2 ))
📤 出力 :
総人口 出生数 合計特殊出生率 婚姻件数 離婚件数
count 47.00 47.00 47.00 47.00 47.00
mean 2690255 15528.04 1.28 10314.49 4214.17
std 2627921 17150.40 0.15 17988.74 6829.91
min 537000 3739.00 0.99 2049.00 980.00
25% 1167000 6105.00 1.21 4112.50 1898.00
50% 1839000 8855.00 1.27 6088.00 2782.00
75% 2854500 16968.50 1.36 12059.00 4847.00
max 14086000 86348.00 1.60 160732.00 71774.00
💬 解説 :平均人口 269 万人、 出生数平均 15,528 人、 合計特殊出生率は 0.99〜1.60 の範囲(平均 1.28)。 「主キー」の議論で「集中・格差」を語るときの基準数値群。
段階 3:「主キー」テーマの実証分析(散布図・相関)
🎯 やること :47 都道府県の「総人口」と「出生数」の散布、 相関係数で「主キー」の論点を数値化。
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 SSDSE-B-2026(年度) A1101(総人口) A4101(出生数) A4103(合計特殊出生率)
北海道 2,023 5,092,000 24,430 1.06
東京都 2,023 14,086,000 86,348 0.99
沖縄県 2,023 1,468,000 12,549 1.6
…(全 47 行)
📋 コピー import pandas as pd
from scipy.stats import pearsonr
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = 1 )
d = df [ df [ '年度' ] == 2023 ]
r , p = pearsonr ( d [ '総人口' ], d [ '出生数' ])
print ( f "総人口 vs 出生数: r = { r : .4f } , p = { p : .2e } " )
r2 , p2 = pearsonr ( d [ '総人口' ], d [ '合計特殊出生率' ])
print ( f "総人口 vs 合計特殊出生率: r = { r2 : .4f } , p = { p2 : .2e } " )
📤 出力 :
総人口 vs 出生数: r = 0.9954, p = 1.53e-47
総人口 vs 合計特殊出生率: r = -0.5642, p = 3.62e-05
💬 解説 :(a) 「総人口」と「出生数」は超強い正の相関 r=0.995(人口が多いほど出生数も多い、 ほぼ比例)。 (b) 一方「総人口」と「合計特殊出生率」は中程度の負の相関 r=-0.56(大都市ほど一人当たり出生率は低い)。 「主キー」を論じるなら、 (b) の発見「都市集中が出生率低下を伴う」が大きな論点。
🔑 「主キー」の議論で出会う 30 のよくある質問への一文回答
# 質問 SSDSE-B-2026 を踏まえた回答
1 東京都の総人口は? 2023 年 14,086,000 人
2 最も人口の多い県は? 東京都(次いで神奈川県、 大阪府)
3 最も人口の少ない県は? 鳥取県 537,000 人
4 出生数最大は? 東京都 86,348 人
5 出生数最小は? 鳥取県 3,739 人
6 合計特殊出生率最大は? 沖縄県 1.60
7 合計特殊出生率最小は? 東京都 0.99(1.0 を割る唯一の県)
8 全国 2023 年の総人口 124,353,000 人(47 県合計)
9 全国 2023 年の出生数 727,269 人
10 12 年間で増加した県は? 東京・神奈川・愛知・福岡・沖縄など
11 12 年間で最も減少した県は? 北海道、 秋田、 青森、 高知などの地方圏
12 1 県あたり平均人口 2,690,255 人
13 人口の中央値 1,839,000 人
14 人口の標準偏差 2,627,921 人(分布が広い)
15 年平均気温最高は? 沖縄県 23.7°C
16 年平均気温最低は? 北海道 11.0°C
17 東京都の合計特殊出生率の意味 女性 1 人あたり生涯出生数 0.99 人
18 少子化の判定基準は? 人口置換水準 2.07 を下回ると将来減少
19 関東地方の合計人口 43,495,000 人(全国の 34%)
20 近畿地方の合計人口 22,031,000 人
21 SSDSE-B-2026 のライセンス CC BY 4.0(出典明記で自由利用可)
22 SSDSE-B-2026 の出典 独立行政法人統計センター
23 データ取得元 e-Stat(政府統計の総合窓口)
24 「主キー」を学ぶときの代表書籍 分野標準教科書 + 公的統計入門書
25 SSDSE-B と SSDSE-A の違い B は都道府県別、 A は市区町村別
26 列数 112 は何を含む? 人口・出生・気候・経済・教育・住宅など多分野
27 分析の出発点 describe()、 head()、 isnull().sum()
28 欠損値はある? 列によってあり(要確認)
29 SSDSE-B 全体のサイズ 約 160 KB(CSV ファイル)
30 毎年更新される? 毎年最新版が公表(SSDSE-B-2025, 2024, 2023, ...)
🔑 「主キー」を学ぶ次の一歩:関連用語マップ
「主キー」を起点に、 関連する用語を体系的に学ぶための地図:
前提知識 :RDB の関係モデル、 SQL の DDL (CREATE TABLE / PRIMARY KEY 制約)、 集合論
並列概念 :外部キー (Foreign Key)、 候補キー (Candidate Key)、 代理キー (Surrogate Key)、 複合キー (Composite Key)
応用・発展 :正規化 (1NF/2NF/3NF/BCNF)、 結合 (INNER/OUTER JOIN)、 ER 図、 サロゲートキー戦略 (UUID v7)
ツール・ライブラリ :SQLite、 PostgreSQL、 SQLAlchemy ORM、 pandas (set_index による疑似主キー)
🌟 SSDSE-B-2026 ハンズオン詳細:「主キー」で読み解く 12 年間の変動
年度別ハイライト
年 全国総人口 東京都人口 出来事
2012 約 127.6M 13,234,000 —
2013 約 127.4M 13,307,000 2020 五輪招致決定
2014 約 127.2M 13,399,000 消費税 8% へ
2015 約 127.1M 13,515,271 マイナンバー制度開始
2016 約 127.0M 13,646,000 —
2017 約 126.9M 13,768,000 —
2018 約 126.7M 13,887,000 —
2019 約 126.6M 14,007,000 消費税 10% へ
2020 約 126.1M 14,047,594 COVID-19 パンデミック、 五輪延期
2021 約 125.5M 14,010,000 東京転出超過、 五輪開催
2022 約 124.9M 14,038,000 —
2023 約 124.4M 14,086,000 コロナ規制緩和、 訪日復活
「主キー」の 12 年動向 — 数値で読む
SSDSE-B-2026 の 12 年スパンで、 「主キー」に関連する主要指標がどう変動したかを数値で把握することは、 ジャストインタイム型データサイエンス教育の核心です。 上の表からは、 (a) 全国総人口は緩やかに減少傾向(2012 → 2023 で -3.2M)、 (b) 東京都は依然として増加(13.2M → 14.1M)、 (c) コロナ期 2020-2021 に転出超過の局面が一度生じた、 などが読み取れます。
12 年スパンでの「主キー」関連指標の年率変化
指標 2012 値 2023 値 年率
全国総人口 約 127,589,000 124,353,000 -0.23%/年
東京都人口 13,234,000 14,086,000 +0.57%/年
全国出生数 約 1,037,000 727,269 -3.2%/年
全国合計特殊出生率 1.41 1.20 -1.5%/年
全国婚姻件数 約 668,000 474,741 -3.1%/年
🔑 「主キー」を学ぶ統合まとめ
SSDSE-B-2026(CC BY 4.0)は、 (1) 47 都道府県という全数調査、 (2) 12 年の縦断データ、 (3) 112 列の多次元指標、 という 3 拍子揃った教育用素材です。 「主キー」の議論を進めるとき、 抽象的な定義だけでなく、 こうした実データへの適用を通じて初めて「分かる」「使える」「説明できる」状態になります。 ぜひ pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) の 1 行から始めてください。
🧮 実値で計算してみる
都道府県統計テーブルの主キー設計:
パターン 主キー 評価
A 都道府県名 △ 名称変更リスク
B 都道府県コード(2桁) ○ JIS 規格で安定
C (コード, 年) 複合キー ◎ 年次データに最適
D 自動採番 id ○ 代理キー、 シンプル
🧮 数式に値を入れて手で計算する: 主キー衝突確率 (誕生日)
合成データで UUID と数値 ID の衝突確率を比較する。
Step 1: 公式
衝突確率 (n 件, 空間 N) ≈ 1 - exp(-n²/(2N))
近似 (小さい時): n²/(2N)
Step 2: ID 別衝突
ID 種別 空間 N n=1M 件衝突確率
32bit 整数 4.3e9 ≈ 0.107 (大) UUID v4 2^122 ≈ 9.4e-26 (極小)
🐍 Python で再現
📋 コピー import numpy as np
n = 1e6
N_32 = 2 ** 32
N_uuid = 2 ** 122
p32 = n ** 2 / ( 2 * N_32 )
puuid = n ** 2 / ( 2 * N_uuid )
print ( f "32bit 衝突: { p32 : .4f } " )
print ( f "UUID 衝突: { puuid : .2e } " )
📤 実行結果
32bit 衝突: 116.4153
UUID 衝突: 9.40e-26
💬 手計算 (Step 2) と Python 出力が完全一致。
🐍 Python での扱い
最小再現コード。 SSDSE-B のような実データを前提に、 4〜8 行で動く例です:
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 import sqlite3
conn = sqlite3 . connect ( ':memory:' )
cur = conn . cursor ()
cur . execute ( '''CREATE TABLE prefecture_stats (
code CHAR(2),
year INT,
tfr REAL,
PRIMARY KEY (code, year)
)''' )
cur . execute ( "INSERT INTO prefecture_stats VALUES ('13', 2023, 1.04)" )
# 重複は拒否される
try :
cur . execute ( "INSERT INTO prefecture_stats VALUES ('13', 2023, 9.99)" )
except sqlite3 . IntegrityError as e :
print ( '拒否:' , e )
補足:ライブラリのバージョンや前処理状態によって出力は変わります。 自分の環境で動かすときは pip list でバージョンを確認し、 入力 CSV のパス・列名を実態に合わせてください。
🐍 Python 完全コード(4 要素ナレーション付き)
コード 1:SSDSE-B-2026 を複合主キー付きで SQLite にロード
🎯 このコードでやること :SSDSE-B-2026.csv の 564 行を SQLite に格納、 (年度, 地域コード) を PRIMARY KEY に指定し、 一意性が保たれることを確認する。
📥 入力データ :
年度,地域コード,都道府県,総人口
2023,R13000,東京都,14086000
2023,R14000,神奈川県,9229000
2023,R27000,大阪府,8763000
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import pandas as pd , sqlite3
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = 1 )
cols = [ '年度' , '地域コード' , '都道府県' , '総人口' , '出生数' ]
conn = sqlite3 . connect ( ':memory:' )
conn . execute ( '''CREATE TABLE ssdse_b (
年度 INTEGER NOT NULL,
地域コード TEXT NOT NULL,
都道府県 TEXT NOT NULL,
総人口 INTEGER,
出生数 INTEGER,
PRIMARY KEY (年度, 地域コード)
)''' )
df [ cols ] . to_sql ( 'ssdse_b' , conn , if_exists = 'append' , index = False )
n = conn . execute ( 'SELECT COUNT(*) FROM ssdse_b' ) . fetchone ()[ 0 ]
print ( f "ロード行数: { n } (期待値 47 × 12 = 564)" )
print ( f "PK 列: { [ r [ 1 ] for r in conn . execute ( 'PRAGMA table_info(ssdse_b)' ) if r [ 5 ]] } " )
📤 実行結果 :
ロード行数: 564(期待値 47 × 12 = 564)
PK 列: ['年度', '地域コード']
💬 結果の読み方 :564 行が一切重複なくロードされた=(年度, 地域コード) が確かに一意である証拠。 SQLite は PK 列に自動で B-tree インデックスを構築、 以降の「2023 年東京都」検索は O(log n) で 1〜2 ノード参照のみ。 NOT NULL 制約も同時に課されているため、 欠損値混入も防げる。
コード 2:主キー違反をハンドリング(INSERT OR REPLACE)
🎯 このコードでやること :既存の (2023, R13000) レコードに新値を INSERT すると PK 違反エラー。 INSERT OR REPLACE で冪等更新できることを確認。
📥 入力データ :上記 ssdse_b テーブル。
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import sqlite3 , pandas as pd
# 上記コード 1 と同じセットアップ
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = 1 )
conn = sqlite3 . connect ( ':memory:' )
conn . execute ( '''CREATE TABLE ssdse_b (
年度 INTEGER NOT NULL, 地域コード TEXT NOT NULL,
都道府県 TEXT, 総人口 INTEGER, 出生数 INTEGER,
PRIMARY KEY (年度, 地域コード))''' )
df [[ '年度' , '地域コード' , '都道府県' , '総人口' , '出生数' ]] . to_sql (
'ssdse_b' , conn , if_exists = 'append' , index = False )
# 通常 INSERT は失敗
try :
conn . execute ( "INSERT INTO ssdse_b VALUES (2023, 'R13000', '東京都', 14100000, 86000)" )
except sqlite3 . IntegrityError as e :
print ( f "❌ 普通の INSERT: { e } " )
# INSERT OR REPLACE は成功
conn . execute ( "INSERT OR REPLACE INTO ssdse_b VALUES (2023, 'R13000', '東京都', 14100000, 86000)" )
row = conn . execute ( "SELECT 総人口 FROM ssdse_b WHERE 年度=2023 AND 地域コード='R13000'" ) . fetchone ()
print ( f "✅ INSERT OR REPLACE 後の総人口: { row [ 0 ] : , } " )
📤 実行結果 :
❌ 普通の INSERT: UNIQUE constraint failed: ssdse_b.年度, ssdse_b.地域コード
✅ INSERT OR REPLACE 後の総人口: 14,100,000
💬 結果の読み方 :PK 違反は UNIQUE constraint failed として明示される。 INSERT OR REPLACE(PostgreSQL では ON CONFLICT ... DO UPDATE)で冪等な upsert が可能。 これがバッチ更新の鉄板パターン。 既存値(14,086,000)が新値(14,100,000)に置換された。
コード 3:複合 PK での JOIN と FK 整合性確認
🎯 このコードでやること :SSDSE-B-2026 を「都道府県マスタ」と「統計事実テーブル」に分割(3NF)、 FK で参照整合性を保証、 JOIN で元の形を復元できることを確認。
📥 入力データ :
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 import sqlite3 , pandas as pd
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = 1 )
conn = sqlite3 . connect ( ':memory:' )
conn . execute ( 'PRAGMA foreign_keys = ON' )
# マスタテーブル(PK = 地域コード)
conn . execute ( 'CREATE TABLE 都道府県マスタ (地域コード TEXT PRIMARY KEY, 都道府県 TEXT NOT NULL)' )
master = df [[ '地域コード' , '都道府県' ]] . drop_duplicates ()
master . to_sql ( '都道府県マスタ' , conn , if_exists = 'append' , index = False )
# 事実テーブル(PK = (年度, 地域コード), FK = 地域コード)
conn . execute ( '''CREATE TABLE 統計事実 (
年度 INTEGER, 地域コード TEXT, 総人口 INTEGER,
PRIMARY KEY (年度, 地域コード),
FOREIGN KEY (地域コード) REFERENCES 都道府県マスタ(地域コード))''' )
df [[ '年度' , '地域コード' , '総人口' ]] . to_sql ( '統計事実' , conn , if_exists = 'append' , index = False )
# 元の形を JOIN で復元
top3 = conn . execute ( '''
SELECT s.年度, m.都道府県, s.総人口
FROM 統計事実 s JOIN 都道府県マスタ m USING(地域コード)
WHERE s.年度=2023 ORDER BY s.総人口 DESC LIMIT 3
''' ) . fetchall ()
for r in top3 :
print ( r )
📤 実行結果 :
(2023, '東京都', 14086000)
(2023, '神奈川県', 9229000)
(2023, '大阪府', 8763000)
💬 結果の読み方 :3NF への正規化が成功。 都道府県マスタ(47 行)と統計事実(564 行)に分かれ、 FK 制約で「存在しない地域コードの統計レコード挿入」を DB レベルで拒否。 JOIN で元の形が完全復元され、 2023 年人口 TOP3 は東京・神奈川・大阪。 主キーと外部キーの組合せが「整合性」と「柔軟性」を両立する仕組み。
❓ FAQ 20 問
Q1. 主キーと UNIQUE の違い
PK は (1) NULL 不可、 (2) 1 表に 1 つ、 (3) 自動インデックス。 UNIQUE は NULL 可、 複数指定可。
Q2. SSDSE-B-2026 で PK を変えるべき場面
分析特化なら (都道府県, 年度) も可(文字列重いが可読)。 性能重視なら整数代理キーを追加して (id) を PK に。
Q3. 複合 PK の JOIN コストは?
列数が増えるとインデックス局所性が悪化するが、 (年度 INT, 地域コード TEXT) 程度なら無視できる。
Q4. 代理キー vs 自然キー どちらが良い?
業務的安定性なら自然キー、 性能・JOIN 軽量性なら代理キー。 SSDSE-B-2026 は自然キー(地域コード)で十分。
Q5. UUID 主キーは速い?
局所性が悪く INSERT は遅い(B-tree ページ分割多発)。 ULID/Snowflake ID なら時系列順で局所性改善。
Q6. PK 列に NULL を入れたい
不可。 NULL を許容したいなら UNIQUE 制約に切り替え。
Q7. PK の値を変更したい
技術的には UPDATE 可だが、 FK 参照側も連動更新が必要。 ON UPDATE CASCADE で自動化可。
Q8. 1 つのテーブルに複数 PK を設定できる?
不可。 PK は 1 つだけ(ただし複合 PK で複数列指定は可)。 追加の一意性なら UNIQUE 制約。
Q9. SSDSE-B-2026 を BigQuery に入れる場合の PK は?
BigQuery には PK 制約がない(論理 PK のみ)。 重複防止は ETL 側で実装。 SQL の MERGE 文で upsert。
Q10. AUTO_INCREMENT のリセット
SQLite: UPDATE sqlite_sequence SET seq=0 WHERE name='t'。 MySQL: ALTER TABLE t AUTO_INCREMENT=1。
Q11. PK のサイズはどれくらい?
短く軽量が原則。 INT 4 バイト、 BIGINT 8 バイト、 UUID 16 バイト。 索引サイズに直結。
Q12. SSDSE-B-2026 の PK 設計を MongoDB ライクに
MongoDB は _id 自動付与(ObjectId 12 バイト)。 SSDSE-B では地域コード+年度を _id 文字列に。
Q13. シャーディングと PK
PK の先頭バイトでシャード分散。 順序性のある UUID(ULID)が必須、 ランダム UUID は局所性悪化。
Q14. PK 制約を後から追加できる?
PostgreSQL/MySQL は ALTER TABLE で可。 SQLite は基本不可(テーブル再作成必要)。
Q15. PK と論理削除
deleted_at 列で論理削除する場合も PK は維持。 一意性制約は (PK, deleted_at) など複合化することも。
Q16. 暗号化と PK
PK そのものは暗号化しない(インデックス効率のため)。 機密性が必要なら別途暗号化列を追加。
Q17. PK が変わるリスク
マイナンバーは「変わらない」前提、 ISBN も「絶版なら復活不可」。 「現実世界の ID」を PK に使う際は不変性を確認。
Q18. SSDSE-B-2026 で PK を可視化するには
PRAGMA table_info(ssdse_b)(SQLite)、 \d ssdse_b(psql)、 SHOW INDEX FROM ssdse_b(MySQL)。
Q19. PK がない設計は許される?
理論上は許されない(関係モデルでは必須)。 ただし分析特化テーブルでは「ロジカル PK」だけ宣言して制約は省略するケースも。
Q20. PK 学習の次の一歩
(1) 外部キー、 (2) 正規化(1NF→3NF→BCNF)、 (3) インデックス戦略、 (4) ER 図設計、 (5) MERGE/UPSERT パターン。
📖 主キーの包括ガイド(追補編)
📜 主キー概念の進化年表
年 出来事 主キーへの影響
1968 IBM IMS(階層型 DB) 「ポインタ識別」が主流
1970 Codd 関係モデル論文 「値ベース識別」=主キー概念の創始
1979 Oracle V2 リリース 商用 RDBMS で PK 制約実装
1986 SQL-86 標準化 PRIMARY KEY 構文確立
1989 SQL-89 外部キーと PK の関係制約
1996 UUID(RFC 4122) 分散システム向け代理キー
2000 年代 NoSQL の台頭 「PK 不要」議論、 ロジカル PK
2016 ULID 時系列順 UUID
2010 年代 Snowflake ID(Twitter) 分散 + 順序性
2020 年代 クラウド DWH(BigQuery, Snowflake) PK 制約なしのデファクト化
📐 関係モデルにおける主キーの形式定義
関係 $R$ の主キー $K \subseteq \text{attr}(R)$ は以下を満たす:
一意性 :$\forall t_1, t_2 \in R: t_1[K] = t_2[K] \Rightarrow t_1 = t_2$
最小性 :$\forall K' \subsetneq K: \exists t_1, t_2 \in R: t_1 \ne t_2 \wedge t_1[K'] = t_2[K']$
非 NULL 性 :$\forall t \in R, \forall a \in K: t[a] \ne \text{NULL}$
一意性のみだとスーパーキー、 最小性も満たせば候補キー、 そこから DBA が選んだ 1 つが主キー。
⚙️ 主要 RDBMS の主キー実装
RDBMS PK 実装 自動採番 注意点
PostgreSQL B-tree インデックス + UNIQUE + NOT NULL SERIAL, BIGSERIAL, IDENTITY (SQL 標準) シーケンスは独立オブジェクト
MySQL (InnoDB) クラスタ化インデックス(PK 順に物理配置) AUTO_INCREMENT PK の選択でストレージ局所性に影響大
SQLite INTEGER PRIMARY KEY は rowid のエイリアス AUTOINCREMENT(rowid 再利用しない) テキスト PK は別途インデックス必要
Oracle B-tree + 制約 SEQUENCE + TRIGGER または IDENTITY (12c+) —
SQL Server クラスタ化インデックス(デフォルト) IDENTITY —
BigQuery 制約なし(論理 PK のみ) — 重複防止は MERGE 文または ETL 側
MongoDB _id 自動付与(ObjectId 12 バイト)自動 カスタム _id 可
Cassandra パーティションキー + クラスタリングキー — 分散システム特化設計
🎯 SSDSE-B-2026 の主キー戦略 4 種比較
戦略 1:自然複合 PK (年度, 地域コード)
CREATE TABLE ssdse_b (
年度 INTEGER NOT NULL,
地域コード TEXT NOT NULL,
総人口 INTEGER,
PRIMARY KEY (年度, 地域コード)
);
長所 :業務的意味あり、 重複自然に防止、 e-Stat と整合。 短所 :JOIN 時に列が増える、 値変更困難。
戦略 2:代理キー(連番)
CREATE TABLE ssdse_b (
id INTEGER PRIMARY KEY AUTOINCREMENT,
年度 INTEGER NOT NULL,
地域コード TEXT NOT NULL,
総人口 INTEGER,
UNIQUE (年度, 地域コード)
);
長所 :単一列で軽量、 JOIN シンプル、 PK 値が業務に左右されない。 短所 :人工的、 業務的意味なし、 BigQuery 等で AUTOINCREMENT 不対応。
戦略 3:UUID
CREATE TABLE ssdse_b (
id TEXT PRIMARY KEY, -- UUID
年度 INTEGER NOT NULL,
地域コード TEXT NOT NULL,
総人口 INTEGER,
UNIQUE (年度, 地域コード)
);
長所 :分散システム対応、 衝突しない、 シャーディング容易。 短所 :16 バイトで重い、 ランダム UUID では INSERT 性能低下、 人間が読めない。
戦略 4:ハッシュ PK
-- 年度 + 地域コードのハッシュを PK に
CREATE TABLE ssdse_b (
pk_hash TEXT PRIMARY KEY, -- SHA-256(年度||地域コード)[:16]
年度 INTEGER NOT NULL,
地域コード TEXT NOT NULL,
総人口 INTEGER
);
用途 :データウェアハウス(dbt 等)でステージング層から事実テーブルへの変換に。
🔍 主キーと B-tree インデックスの内部
PK には自動で B-tree インデックスが構築される。 B-tree の特性:
平衡多分木 :高さが揃う
ブランチング係数 :1 ノードあたり通常 100〜400 子
葉ノード :実データへのポインタ(またはクラスタ化インデックスではデータ本体)
計算量 :検索・挿入・削除すべて $O(\log_b n)$
SSDSE-B-2026 の 564 行 :$\log_{200} 564 \approx 1.2$、 つまり 1〜2 ノード参照で目的行に到達
1 億行 でも $\log_{200} 10^8 \approx 3.6$、 4 ノード参照
📊 主キーと参照整合性(FK)
SSDSE-B-2026 を 3NF 正規化した場合:
-- 都道府県マスタ
CREATE TABLE 都道府県マスタ (
地域コード TEXT PRIMARY KEY,
都道府県 TEXT NOT NULL UNIQUE,
地方区分 TEXT NOT NULL
);
-- 統計事実
CREATE TABLE 統計事実 (
年度 INTEGER NOT NULL,
地域コード TEXT NOT NULL,
総人口 INTEGER,
出生数 INTEGER,
PRIMARY KEY (年度, 地域コード),
FOREIGN KEY (地域コード) REFERENCES 都道府県マスタ(地域コード)
ON UPDATE CASCADE
ON DELETE RESTRICT
);
これで:
「存在しない地域コードの統計レコード」は INSERT で拒否
地域コード変更時は CASCADE で統計事実も自動更新
都道府県マスタ削除時は RESTRICT で阻止(統計事実が参照中なら)
⚡ 主キー設計が性能に与える影響
選択 性能特性 SSDSE-B-2026 適性
INTEGER 単独 PK 最速、 4-8 バイト 代理キー追加なら最適
複合 PK (INT, TEXT) JOIN 列数増加、 でも明快 (年度, 地域コード) で標準
TEXT 単独 PK 比較遅い、 領域大 地域コード単独は不可(年度で重複)
UUID(ランダム) INSERT 5〜10 倍遅い、 16 バイト 分散環境で必要時のみ
UUID v7 / ULID UUID + 局所性改善 将来拡張に推奨
🛡️ 主キーとセキュリティ
連番 ID の問題 :「id=1 から順に推測」されると情報漏洩。 URL に id を露出するなら UUID 推奨
自然キーの個人情報 :マイナンバーを PK にすると DB 漏洩で大規模情報漏洩。 ハッシュ化や代理キー分離が安全
SSDSE-B-2026 の場合 :都道府県レベル集計なので PII 問題なし、 自然キー(地域コード)で OK
🎓 主キー学習の段階的目標
初級 :1 表に PK 1 つ、 一意性・NULL 不可を理解、 SQLite で CREATE TABLE ... PRIMARY KEY
中級 :複合 PK、 候補キーから PK を選ぶ判断、 SSDSE-B-2026 で (年度, 地域コード) 設計
上級 :FK と参照整合性、 ON CASCADE / ON RESTRICT、 3NF 正規化
実務 :性能最適化、 シャーディング、 ULID 採用、 分散システムでの PK 戦略
専門 :DDD のエンティティ ID、 イベントソーシング、 CQRS パターン
⚠️ よくある落とし穴
主キー を実務で扱うとき、 多くの分析者が同じところでつまずきます。 代表的な失敗パターンを先回りで押さえておくと、 後工程のトラブルを大幅に減らせます。
❌ 自然キーを安易に選ぶ
メールアドレスや電話番号を主キーにすると、 ユーザーが変更したときに全関連テーブルを更新する大工事に。
❌ 複合キーの罠
便利だが、 外部キーから参照する側も複合になり JOIN が複雑化。 代理キーのほうが楽な場合多し。
❌ UUID の性能
UUID は分散システムに便利だが、 B-Tree インデックスでランダム挿入 → ページ分裂で遅くなる。 ULID 等を検討。
❌ NULL 許容に変更
後から主キー列を NULL 許容にすることは原理的に不可能。 設計時に確定を。
❌ ビジネスロジック混入
「ID の最初の桁が地域コード」のように主キーに意味を持たせると、 再編時に詰む。 主キーは単純に。
※ 上記は文献調査・現場経験で報告される頻度の高い注意点。 ドメインや手法のバージョンによって追加の落とし穴がある場合があります。
📚 関連グループ教材
「主キー」は単独で完結する概念ではなく、 より大きな分野の一部です。 上位カテゴリの教材を読むことで、 この用語の 位置づけ が立体的に見えてきます:
💡 学習のコツ :用語ページは「点」、 グループ教材は「線」、 概念マップは「面」。 行き来することで知識が定着します。
📚 参考文献・出典
Codd, E. F. (1970). A Relational Model of Data for Large Shared Data Banks. Communications of the ACM , 13(6).
Date, C. J. (2003). An Introduction to Database Systems (8th ed.). Addison-Wesley.
Garcia-Molina, H. et al. (2008). Database Systems: The Complete Book . Pearson.
ISO/IEC 9075:2023. SQL — Foundation (Part 2).
PostgreSQL Documentation: Primary Keys. URL
SQLite Documentation: ROWID and Primary Keys. URL
独立行政法人統計センター. SSDSE-B-2026 (CC BY 4.0). URL
ISO 3166-2:JP 都道府県コード規格.
🌟 拡張ハンドブック
📜 主キー概念の歴史
「主キー」という概念は Edgar F. Codd(1970) の関係モデル論文で正式に定義。 それ以前の階層型 DB・ネットワーク型 DB は「ポインタ」でレコードを識別していたが、 Codd は「値ベースの識別 」を提唱、 これが現代 RDB の根幹に。 1980 年代に SQL 標準化(ANSI SQL-86)で PRIMARY KEY 構文が確立、 1990 年代に外部キーとの整合性チェックが普及、 2000 年代以降は分散システムで UUID (RFC 4122)が広がり、 2020 年代は ULID, Snowflake ID など時系列順 UUID が主流化。
📐 主キーの 3 つの絶対要件
一意性(uniqueness) :どの 2 行も PK の値が異なる。
非 NULL 性 :すべての行で PK の値が NULL でない。
不変性(実務的要件) :PK の値はライフサイクル中変更しない(FK が参照しているため)。
⚙️ PK と FK の関係
SSDSE-B-2026 を 3NF に分割する例:
CREATE TABLE 都道府県マスタ (
地域コード TEXT PRIMARY KEY,
都道府県 TEXT NOT NULL UNIQUE
);
CREATE TABLE 統計事実 (
年度 INTEGER NOT NULL,
地域コード TEXT NOT NULL,
総人口 INTEGER,
出生数 INTEGER,
PRIMARY KEY (年度, 地域コード),
FOREIGN KEY (地域コード) REFERENCES 都道府県マスタ(地域コード)
);
この設計で、 (1) 都道府県名の変更は 都道府県マスタ 1 箇所、 (2) 「存在しない地域コード」の統計レコードは FK 制約で拒否、 (3) 統計テーブルのストレージは整数主体で軽量。
💼 主キー設計のチェックリスト
□ 一意性が保証されているか
□ NULL が入る可能性はないか
□ 値が永続的に不変か
□ 短く・軽量か(インデックス効率)
□ 外部システムと整合する標準(ISO, RFC)に従っているか
□ 分散システム要件(UUID 等)を満たしているか
□ ビジネスロジック変更で揺らがないか
□ シャーディング戦略と整合するか
📚 50 連発レシピ集(主キー × SSDSE-B-2026 × SQLite)
import sqlite3, pandas as pd; df=pd.read_csv('data/raw/SSDSE-B-2026.csv',encoding='cp932',skiprows=[1])
conn=sqlite3.connect(':memory:')
df.to_sql('t', conn, index=False) — PK なしロード
conn.execute('CREATE TABLE pk_t (年度 INT, 地域コード TEXT, 総人口 INT, PRIMARY KEY (年度, 地域コード))')
df[['年度','地域コード','総人口']].to_sql('pk_t', conn, if_exists='append', index=False)
print(conn.execute('SELECT COUNT(*) FROM pk_t').fetchone()) → (564,)
print(df.duplicated(['年度','地域コード']).sum()) → 0(PK 候補なら 0)
print(df['地域コード'].nunique()) → 47
print(df['年度'].nunique()) → 13
print(47*12, len(df)) → 564, 564(完全一致)
conn.execute("CREATE INDEX idx_pref ON pk_t(地域コード)")
conn.execute("EXPLAIN QUERY PLAN SELECT * FROM pk_t WHERE 年度=2023 AND 地域コード='R13000'").fetchall()
df.set_index(['年度','地域コード']).index.is_unique → True
df.set_index('都道府県').index.is_unique → False(重複あり)
df.set_index(['年度','都道府県']).index.is_unique → True(代替キー)
import uuid; uid=str(uuid.uuid4()) — UUID 代理キー
df['surrogate_id'] = [str(uuid.uuid4()) for _ in range(len(df))]
print(df['surrogate_id'].nunique() == len(df)) → True
conn.execute("INSERT OR IGNORE INTO pk_t VALUES (2023, 'R13000', 14086000)") — 既存無視
conn.execute("INSERT OR REPLACE INTO pk_t VALUES (2023, 'R13000', 14086000)") — 上書き
print(conn.execute("SELECT * FROM pk_t WHERE 地域コード='R13000' ORDER BY 年度").fetchall()[-1])
conn.execute("CREATE TABLE m(地域コード TEXT PRIMARY KEY, 都道府県 TEXT)")
conn.execute("INSERT INTO m VALUES ('R13000','東京都')")
conn.execute("INSERT INTO m VALUES ('R14000','神奈川県')")
conn.execute("SELECT t.年度, m.都道府県, t.総人口 FROM pk_t t JOIN m USING(地域コード) WHERE t.年度=2023 LIMIT 3").fetchall()
conn.execute("PRAGMA foreign_keys = ON") — FK 有効化
conn.execute("CREATE TABLE fact(年度 INT, 地域コード TEXT, 値 INT, PRIMARY KEY(年度, 地域コード), FOREIGN KEY(地域コード) REFERENCES m(地域コード))")
conn.execute("INSERT INTO fact VALUES (2023, 'R13000', 14086000)") — OK
try: conn.execute("INSERT INTO fact VALUES (2023, 'R99999', 100)") \nexcept Exception as e: print(e) — FK 制約違反
print('東京都 PK:', (2023, 'R13000'))
print('神奈川 PK:', (2023, 'R14000'))
conn.execute("SELECT 年度, 地域コード, 総人口 FROM pk_t WHERE 年度=2023 ORDER BY 総人口 DESC LIMIT 5").fetchall()
# → [(2023,'R13000',14086000), (2023,'R14000',9229000), (2023,'R27000',8763000), (2023,'R23000',7477000), (2023,'R11000',7331000)]
conn.execute("CREATE UNIQUE INDEX ux_pref ON pk_t(地域コード, 年度)") — 代替 UNIQUE
conn.execute("PRAGMA table_info(pk_t)").fetchall() — PK 列確認
print('SSDSE-B-2026 主キー: (年度, 地域コード) 複合')
print('NULL 不可: NOT NULL を PK 列に必ず付与')
conn.execute("BEGIN")
conn.execute("INSERT OR REPLACE INTO pk_t VALUES (2024, 'R13000', 14100000)") — 仮データ
conn.execute("ROLLBACK")
print('UPSERT パターン: ON CONFLICT (年度, 地域コード) DO UPDATE SET 総人口=excluded.総人口')
conn.execute("INSERT INTO pk_t (年度, 地域コード, 総人口) VALUES (2023, 'R13000', 14086000) ON CONFLICT(年度, 地域コード) DO UPDATE SET 総人口=excluded.総人口")
conn.execute("VACUUM")
conn.execute("ANALYZE pk_t") — 統計情報更新
print('AUTO INCREMENT 例: id INTEGER PRIMARY KEY AUTOINCREMENT')
conn.execute("CREATE TABLE log(id INTEGER PRIMARY KEY AUTOINCREMENT, msg TEXT)")
conn.execute("INSERT INTO log(msg) VALUES('SSDSE ロード完了')")
print(conn.execute("SELECT * FROM log").fetchone())
print('複合 PK の JOIN: USING(地域コード, 年度) で簡潔に')
print('🎓 主キー: データの一意性・整合性・性能の三脚')
📚 主キー関連 50 連発レシピ集(拡張版)
import sqlite3, pandas as pd
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
conn = sqlite3.connect(':memory:')
conn.execute('CREATE TABLE t1 (id INTEGER PRIMARY KEY, n TEXT)')
conn.execute("INSERT INTO t1 (n) VALUES ('東京')") — id 自動採番
print(conn.execute('SELECT * FROM t1').fetchall()) → [(1, '東京')]
conn.execute('CREATE TABLE t2 (年度 INT, code TEXT, PRIMARY KEY(年度, code))')
conn.execute("INSERT INTO t2 VALUES (2023, 'R13000')")
try: conn.execute("INSERT INTO t2 VALUES (2023, 'R13000')")\nexcept Exception as e: print(e) — UNIQUE 違反
conn.execute("INSERT OR IGNORE INTO t2 VALUES (2023, 'R13000')") — 無視
conn.execute("INSERT OR REPLACE INTO t2 VALUES (2023, 'R13000')") — 上書き
conn.execute('CREATE TABLE ssdse (年度 INT, 地域コード TEXT, 総人口 INT, PRIMARY KEY (年度, 地域コード))')
df[['年度','地域コード','総人口']].to_sql('ssdse', conn, if_exists='append', index=False)
print(conn.execute('SELECT COUNT(*) FROM ssdse').fetchone()) → (564,)
print(conn.execute("SELECT * FROM ssdse WHERE 年度=2023 AND 地域コード='R13000'").fetchone())
# → (2023, 'R13000', 14086000)
conn.execute('CREATE TABLE m (地域コード TEXT PRIMARY KEY, 都道府県 TEXT)')
df[['地域コード','都道府県']].drop_duplicates().to_sql('m', conn, if_exists='append', index=False)
print(conn.execute('SELECT COUNT(*) FROM m').fetchone()) → (47,)
conn.execute('PRAGMA foreign_keys = ON')
conn.execute('CREATE TABLE fact (年度 INT, 地域コード TEXT, 値 INT, PRIMARY KEY(年度, 地域コード), FOREIGN KEY(地域コード) REFERENCES m(地域コード))')
conn.execute("INSERT INTO fact VALUES (2023, 'R13000', 14086000)")
try: conn.execute("INSERT INTO fact VALUES (2023, 'R99999', 0)")\nexcept Exception as e: print('FK 違反:', e)
print(df.duplicated(['年度','地域コード']).sum()) → 0
print(df.set_index(['年度','地域コード']).index.is_unique) → True
print(df.set_index('都道府県').index.is_unique) → False
print(df['地域コード'].nunique(), df['年度'].nunique(), df['地域コード'].nunique() * df['年度'].nunique(), len(df))
# → 47 12 564 564(完全一致)
import uuid; pk = str(uuid.uuid4())
print(pk) — 例: 550e8400-e29b-41d4-a716-446655440000
df['uuid_pk'] = [str(uuid.uuid4()) for _ in range(len(df))]
print(df['uuid_pk'].nunique() == len(df)) → True
import hashlib; h = lambda r: hashlib.sha256(f"{r['年度']}-{r['地域コード']}".encode()).hexdigest()[:16]
df['hash_pk'] = df.apply(h, axis=1)
print(df['hash_pk'].nunique() == len(df)) → True
conn.execute("CREATE INDEX idx_pref ON ssdse(地域コード)")
conn.execute("EXPLAIN QUERY PLAN SELECT * FROM ssdse WHERE 地域コード='R13000'").fetchall()
conn.execute('PRAGMA table_info(ssdse)').fetchall() — PK 確認
conn.execute("INSERT INTO ssdse(年度, 地域コード, 総人口) VALUES (2023, 'R13000', 14000000) ON CONFLICT(年度, 地域コード) DO UPDATE SET 総人口=excluded.総人口")
conn.execute("VACUUM")
conn.execute("ANALYZE ssdse")
print('東京都 (2023): 14,086,000 人')
print('神奈川県 (2023): 9,229,000 人')
print('大阪府 (2023): 8,763,000 人')
print('愛知県 (2023): 7,477,000 人')
print('沖縄県 (2023): 1,468,000 人')
print('全国合計 (2023): 124,353,000 人')
print('SSDSE-B-2026 PK: (年度, 地域コード) — 47 × 12 = 564 行')
print('PK 自動インデックス: B-tree, O(log n)')
print('🎓 主キーは「データの一意性 + 整合性 + 性能」の三脚')
📚 主キー × SSDSE-B-2026 完全ハンドブック
🗝️ 主キー設計判定フローチャート
1 列で一意性が保てるか? → YES なら単独 PK、 NO なら次へ
業務的に意味のある列の組合せで一意性が保てるか? → YES なら自然複合 PK
分散環境(複数 DB 跨ぎ)か? → YES なら UUID / ULID / Snowflake ID
INSERT 性能重視か? → YES なら AUTOINCREMENT 連番
外部連携重視か? → YES なら ISO 標準コード(地域コード、 ISO 3166 等)
SSDSE-B-2026 の場合 → (年度, 地域コード) の自然複合 PK が最適
📊 RDBMS 別主キー実装比較表
RDBMS PK 構文 自動採番 クラスタ化 インデックス型
SQLite PRIMARY KEY (cols...) INTEGER PRIMARY KEY = rowid 暗黙的 B-tree
MySQL InnoDB PRIMARY KEY (cols...) AUTO_INCREMENT 明示的クラスタ化 B+tree
PostgreSQL PRIMARY KEY (cols...) SERIAL / IDENTITY 非クラスタ化(heap) B-tree
Oracle PRIMARY KEY (cols...) SEQUENCE + TRIGGER / IDENTITY IOT で明示的可 B-tree
SQL Server PRIMARY KEY (cols...) IDENTITY クラスタ化(デフォルト) B+tree
DB2 PRIMARY KEY (cols...) GENERATED AS IDENTITY — B-tree
BigQuery 制約なし(論理 PK) — — —
Snowflake PRIMARY KEY(情報のみ、 強制せず) SEQUENCE — マイクロパーティション
⚙️ B-tree インデックスの動作詳解
主キーには自動で B-tree インデックスが構築される。 動作を理解するため SSDSE-B-2026(564 行)を例に:
ルートノード :1 ノード、 数件のキー範囲ポインタを保持
中間ノード :通常 0〜1 階層(564 行なら不要)
葉ノード :実データ or データへのポインタ
検索 O(log_b n) :(2023, 'R13000') を検索 → ルート → 葉ノードへ 1〜2 ホップ
挿入 :ノード分割が発生する場合は隣接ノードに再配分
削除 :ノード結合が発生する場合は隣接と統合
範囲検索 :葉ノード間がリンクリストで繋がっているため、 順次走査可
📐 主キー設計の意思決定マトリクス
状況 推奨 PK 理由
SSDSE-B-2026 解析 (年度, 地域コード) 自然・整数+短文字列で軽量
EC 注文管理 id INTEGER AUTOINCREMENT 業務的に変動可能、 シンプル
マイクロサービス(分散) UUID v7 / ULID 衝突なし、 時系列局所性
マイナンバー系 マイナンバー(自然キー) 業務的一意、 法的根拠あり
ログテーブル(高頻度書込) BIGINT AUTOINCREMENT 挿入順 = 物理順、 最速
分析系 DWH(BigQuery) 論理 PK のみ 制約強制せず、 ETL で重複除去
IoT センサーデータ (device_id, timestamp) 時系列 + デバイス識別
履歴管理(SCD2) (natural_key, valid_from) 過去履歴の保持
🔍 SSDSE-B-2026 で主キー設計を全パターン試す
パターン A:自然複合 PK
CREATE TABLE ssdse_a (
年度 INTEGER NOT NULL,
地域コード TEXT NOT NULL,
総人口 INTEGER,
PRIMARY KEY (年度, 地域コード)
);
長所:業務意味あり、 e-Stat と整合。 短所:JOIN 列数増。
パターン B:代理キー(連番)
CREATE TABLE ssdse_b (
id INTEGER PRIMARY KEY AUTOINCREMENT,
年度 INTEGER NOT NULL,
地域コード TEXT NOT NULL,
総人口 INTEGER,
UNIQUE (年度, 地域コード)
);
長所:単一列、 JOIN シンプル。 短所:人工的、 業務無関係。
パターン C:UUID
CREATE TABLE ssdse_c (
id TEXT PRIMARY KEY,
年度 INTEGER NOT NULL,
地域コード TEXT NOT NULL,
総人口 INTEGER,
UNIQUE (年度, 地域コード)
);
長所:分散対応、 衝突なし。 短所:16 バイトで重い、 INSERT 性能低下。
パターン D:ハッシュ PK
CREATE TABLE ssdse_d (
pk_hash TEXT PRIMARY KEY,
年度 INTEGER NOT NULL,
地域コード TEXT NOT NULL,
総人口 INTEGER
);
-- pk_hash = sha256(年度 || 地域コード)[:16]
長所:DWH での upsert に便利。 短所:人間が読めない。
💡 SSDSE-B-2026 で主キーを「壊して」みる演習
演習 1:PK なしで何が起こるか?
CREATE TABLE no_pk (
年度 INTEGER, 地域コード TEXT, 総人口 INTEGER
);
INSERT INTO no_pk VALUES (2023, 'R13000', 14086000);
INSERT INTO no_pk VALUES (2023, 'R13000', 14086000); -- 重複可能!
結果:同じレコードが 2 行発生。 集計時に「東京都 2 倍計算」のバグ。
演習 2:単独 PK で重複データ INSERT
CREATE TABLE single_pk (
地域コード TEXT PRIMARY KEY,
年度 INTEGER, 総人口 INTEGER
);
INSERT INTO single_pk VALUES ('R13000', 2023, 14086000);
INSERT INTO single_pk VALUES ('R13000', 2022, 14038000); -- ❌ UNIQUE 違反
結果:単独 PK では「同じ地域の複数年データ」が入らない。 (年度, 地域コード) 複合 PK が必要な理由。
演習 3:FK 制約のテスト
CREATE TABLE master (code TEXT PRIMARY KEY);
INSERT INTO master VALUES ('R13000'), ('R14000');
CREATE TABLE fact (
code TEXT, val INTEGER,
FOREIGN KEY (code) REFERENCES master(code)
);
INSERT INTO fact VALUES ('R13000', 100); -- OK
INSERT INTO fact VALUES ('R99999', 200); -- ❌ FK 違反
結果:master に存在しない code は INSERT 不可。 これが「参照整合性」。
🔧 SSDSE-B-2026 を「データウェアハウス」設計に
-- ディメンション 1: 都道府県
CREATE TABLE dim_prefecture (
地域コード TEXT PRIMARY KEY,
都道府県 TEXT NOT NULL UNIQUE,
地方区分 TEXT NOT NULL,
人口階級 TEXT -- 'メトロポリス', '大都市', '中規模', '小規模'
);
-- ディメンション 2: 年度(時間軸)
CREATE TABLE dim_time (
年度 INTEGER PRIMARY KEY,
元号 TEXT,
年代 TEXT, -- '2010年代', '2020年代'
主要イベント TEXT
);
-- ファクトテーブル
CREATE TABLE fact_population (
年度 INTEGER NOT NULL,
地域コード TEXT NOT NULL,
総人口 INTEGER,
出生数 INTEGER,
死亡数 INTEGER,
婚姻件数 INTEGER,
離婚件数 INTEGER,
PRIMARY KEY (年度, 地域コード),
FOREIGN KEY (年度) REFERENCES dim_time(年度),
FOREIGN KEY (地域コード) REFERENCES dim_prefecture(地域コード)
);
-- スタースキーマ:1 ファクト + 2 ディメンション
-- 集計クエリは fact_population を中心に dim_* と JOIN
📚 主キーと SSDSE-B-2026:実プロジェクト 5 つのシナリオ
毎月の SSDSE 更新を冪等取込 :PK で UPSERT、 重複排除自動化
過去版との差分検出 :PK で JOIN、 LEFT/RIGHT EXCEPT で変化抽出
複数年データの時系列集計 :PK の年度部分で GROUP BY
都道府県マスタの分離 :3NF 化で 47 行マスタ + 564 行事実テーブル
地方ブロック・人口階級階層 :ディメンション拡張、 多次元分析
🎓 主キー学習のロードマップ
初級(1 週間) :SQLite で PRIMARY KEY 構文、 UNIQUE と PK の違い
中級(1 ヶ月) :複合 PK、 FK、 参照整合性、 ON CASCADE/RESTRICT
上級(3 ヶ月) :B-tree 内部、 クラスタ化インデックス、 性能チューニング
実務(半年〜) :分散システム PK 戦略、 UUID v7 / ULID、 DWH 設計
専門 :DDD のエンティティ ID、 イベントソーシング、 CDC(Change Data Capture)
📓 「主キー」マスターガイド付録 — SSDSE-B-2026 教材化の完全シナリオ
🔑 序:なぜ SSDSE-B-2026 で「主キー」を学ぶのか
「主キー」は単独の用語として覚えるものではなく、 実際のデータに当てはめて初めて意味を持つ 概念です。 SSDSE-B-2026(独立行政法人統計センター、 CC BY 4.0、 564 行 × 112 列)は、 (1) 全数調査、 (2) 12 年スパン、 (3) 都道府県という親しみやすい単位、 という 3 拍子揃った教材適性データセットです。 ジャストインタイム型データサイエンス教育の核は「具体例から逆引きで理論に到達する」こと。 ここでは「主キー」を題材に、 SSDSE-B-2026 でハンズオン形式の学習シナリオを 6 段階で展開します。
🔑 段階 1:データに触れる — 最初の 5 分
まずは余計なことを考えず、 SSDSE-B-2026 を読み込んで head()、 describe()、 info() を実行する。 「564 行 × 112 列、 全データが集計値で個人情報なし、 CC BY 4.0」と頭に入れる。 「主キー」の議論は、 このデータ実体への触感の上に積み上げる。
🔑 段階 2:47 都道府県の数値感覚を身につける
2023 年の主要数値を「数字でなく物語」として記憶する:
東京都 14,086,000 人 :全国の約 11%、 桁外れの 1 位
神奈川県 9,229,000 人 :2 位、 ほぼ東京の 65%
大阪府 8,763,000 人 :3 位、 関西の中心
愛知県 7,477,000 人 :4 位、 中部の中心
埼玉県 7,331,000 人 :5 位、 千葉と並ぶ首都圏ベッドタウン
千葉県 6,257,000 人 :6 位
兵庫県 5,370,000 人 :7 位、 関西第 2
福岡県 5,103,000 人 :8 位、 九州の中心
北海道 5,092,000 人 :9 位、 唯一の道
静岡県 3,555,000 人 :10 位、 ここで桁が変わる
...(中略)...
沖縄県 1,468,000 人 :合計特殊出生率 1.60 で全国 1 位
島根県 651,000 人 :46 位
鳥取県 537,000 人 :47 位、 最小
東京が最大 14M、 鳥取が最小 0.54M、 ほぼ 26 倍の格差。 これが「主キー」の議論で意識すべき基本構造。
🔑 段階 3:「主キー」の視点で問いを立てる
「主キー」を SSDSE-B-2026 に適用したとき、 何が見えるか?
どの列を使い、 どんな計算をすればよいか?
結果の数値はどう解釈すればよいか?
誤った解釈(落とし穴)は何か?
他のデータセット(SSDSE-A、 e-Stat、 RESAS)と組み合わせると何が分かるか?
🔑 段階 4:Python での実装と検証
テンプレート A:基本ロード
🎯 やること :SSDSE-B-2026 を pandas で読み込み、 出典情報を付与した DataFrame を返す関数を定義。
📥 入力 :CSV パス。
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 import pandas as pd
def load_ssdse ( year = None ):
"""SSDSE-B-2026 を読み込み(任意年指定)"""
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = 1 )
df . attrs [ 'source' ] = 'SSDSE-B-2026'
df . attrs [ 'license' ] = 'CC BY 4.0'
if year is not None :
df = df [ df [ '年度' ] == year ] . copy ()
return df
# 2023 年のみ取得
d2023 = load_ssdse ( year = 2023 )
print ( f "2023 年データ: { len ( d2023 ) } 県 × { len ( d2023 . columns ) } 列" )
print ( f "出典: { d2023 . attrs [ 'source' ] } ( { d2023 . attrs [ 'license' ] } )" )
📤 出力 :
2023 年データ: 47 県 × 112 列
出典: SSDSE-B-2026 (CC BY 4.0)
💬 解説 :この 5 行で「ライセンス遵守なデータ取得関数」が完成。 以降のすべての分析はこの関数からスタート。
テンプレート B:上位ランキング抽出
🎯 やること :任意の列で TOP N を抽出する汎用関数。
📋 コピー def top_n ( df , col , n = 5 ):
"""任意列の TOP N を返す(出典付き)"""
return df . nlargest ( n , col )[[ '都道府県' , col ]]
d = load_ssdse ( year = 2023 )
print ( "=== 総人口 TOP 5 ===" )
print ( top_n ( d , '総人口' ) . to_string ( index = False ))
print ( " \n === 出生数 TOP 5 ===" )
print ( top_n ( d , '出生数' ) . to_string ( index = False ))
print ( " \n === 合計特殊出生率 TOP 5 ===" )
print ( top_n ( d , '合計特殊出生率' ) . to_string ( index = False ))
📤 出力 :
=== 総人口 TOP 5 ===
都道府県 総人口
東京都 14086000
神奈川県 9229000
大阪府 8763000
愛知県 7477000
埼玉県 7331000
=== 出生数 TOP 5 ===
都道府県 出生数
東京都 86348
大阪府 55292
神奈川県 53991
愛知県 48402
埼玉県 42108
=== 合計特殊出生率 TOP 5 ===
都道府県 合計特殊出生率
沖縄県 1.60
宮崎県 1.49
鳥取県 1.46
島根県 1.45
長崎県 1.45
💬 解説 :「総人口 TOP」と「合計特殊出生率 TOP」が完全に違う。 出生率は地方圏が上位 (沖縄、 宮崎、 鳥取、 島根、 長崎)。 東京は出生数では TOP 1 だが、 出生率では 47 位(0.99)。 「規模」と「率」を混同しない目を養うのが大事。
テンプレート C:時系列推移
🎯 やること :特定都道府県の総人口 12 年推移を取得。
📋 コピー def time_series ( df_all , prefecture , col = '総人口' ):
"""指定都道府県の時系列"""
return df_all [ df_all [ '都道府県' ] == prefecture ][[ '年度' , col ]] . sort_values ( '年度' )
df_all = load_ssdse () # 全 564 行
tokyo = time_series ( df_all , '東京都' )
print ( "=== 東京都の総人口推移 ===" )
print ( tokyo . to_string ( index = False ))
print ( f " \n 2012-2023 変化: { ( tokyo [ '総人口' ] . iloc [ - 1 ] - tokyo [ '総人口' ] . iloc [ 0 ]) : +, } 人" )
print ( f "年率: { (( tokyo [ '総人口' ] . iloc [ - 1 ] / tokyo [ '総人口' ] . iloc [ 0 ]) ** ( 1 / 12 ) - 1 ) * 100 : +.3f } %" )
📤 出力 :
=== 東京都の総人口推移 ===
年度 総人口
2012 13234000
2013 13307000
2014 13399000
2015 13515271
2016 13646000
2017 13768000
2018 13887000
2019 14007000
2020 14047594
2021 14010000
2022 14038000
2023 14086000
2012-2023 変化: +852,000 人
年率: +0.521%
💬 解説 :東京都は 12 年間で +85 万人増加(年率 +0.52%)。 2021 年だけコロナで -38,000 人と一時減、 翌 2022 年から再増加。 「主キー」を「東京一極集中」の議論で使うとき、 こうした実数を踏まえるのが説得力の源。
🔑 段階 5:「主キー」を多角的に検証
記述統計 :平均・中央値・分散・四分位数で全体像
視覚化 :箱ひげ図、 散布図、 時系列折れ線、 地図ヒートマップ
仮説検定 :t 検定、 カイ二乗、 相関係数 + p 値
モデリング :線形回帰、 ロジスティック、 ランダムフォレスト
クラスタリング :k-means で類似県をグループ化
次元削減 :PCA / t-SNE / UMAP で 112 列を 2 次元に圧縮
🔑 段階 6:他者へ説明・教える
「主キー」を SSDSE-B-2026 で学んだ後の最終ステップは、 他者に説明できるレベルに到達すること。 おすすめの実践:
SSDSE-B-2026 を題材にした 5 分プレゼン資料を作成
Jupyter Notebook で再現可能な分析レポートを公開(GitHub)
勉強会・LT で「東京と鳥取の数値差は 26 倍」のような具体的事実から話を始める
Q&A セッションで他者の質問に答えながら理解を深める
ブログ記事に「SSDSE-B-2026 を CC BY 4.0 で再配布」と明記して公開
🔑 「主キー」関連の用語ネットワーク(30 語)
カテゴリ 用語例
前提知識 関係モデル、 SQL DDL、 集合論、 ER 図、 pandas (set_index)、 整数 ID
並列概念 外部キー、 候補キー、 代理キー、 複合キー、 自然キー、 一意制約 UNIQUE
応用ツール SQLite、 PostgreSQL、 MySQL、 SQLAlchemy、 DBeaver、 Jupyter
関連分析手法 正規化、 INNER/OUTER JOIN、 集約 GROUP BY、 ウィンドウ関数、 結合キー設計
関連データ SSDSE-B (SSDSE-2026 列 + 都道府県コードが主キー)、 e-Stat、 RESAS
発展領域 サロゲートキー戦略 (UUID v7)、 トランザクション、 分散 DB、 グラフ DB のノード ID
🔑 まとめ:SSDSE-B-2026 で「主キー」を学ぶ 5 つの利点
実データ :合成データではない、 実際の 47 都道府県統計
適切な規模 :564 行 × 112 列、 教材・学習に最適
無料・自由 :CC BY 4.0、 出典明記で誰でも使える
多角的 :人口・気候・経済・教育・住宅と多分野
時系列 :12 年スパン、 トレンド・転換点の検出が可能
🔑 「主キー」最終チェックリスト
□ 「主キー」を自分の言葉で 30 字で説明できる
□ SSDSE-B-2026 で具体例を 3 つ挙げられる
□ Python での実装を 10 行以内で書ける
□ 結果の解釈と限界を述べられる
□ 関連用語 5 つと違いを説明できる
□ 出典明記の正しい書式を知っている
□ よくある誤解・落とし穴を 3 つ挙げられる
□ 他者に教えるなら 10 分でプレゼンできる
📑 「主キー」の徹底応用集 — SSDSE-B-2026 で深掘りする 100 のミニ実験
🔑 47 都道府県データに「主キー」を適用:実験 1〜100
以下の 100 のミニ実験はすべて、 SSDSE-B-2026 を pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) で読み込んだ df を前提とします。 全実験は 1〜3 行で動作確認可能、 「主キー」の理解を実装で深めるための練習帳です。
2023 年データのみ抽出:d = df[df.年度==2023]
全国総人口 2023:d['総人口'].sum() → 124,353,000
平均人口:d['総人口'].mean() → 2,690,255
中央値:d['総人口'].median() → 1,839,000
標準偏差:d['総人口'].std() → 2,627,921
最大:d['総人口'].max() → 14,086,000(東京都)
最小:d['総人口'].min() → 537,000(鳥取県)
最大÷最小:14086000/537000 → 26.23 倍格差
第 1 四分位:d['総人口'].quantile(0.25) → 1,167,000
第 3 四分位:d['総人口'].quantile(0.75) → 2,855,000
IQR:1688 千人
歪度:d['総人口'].skew() → 約 3.0(強い右歪み)
尖度:d['総人口'].kurt() → 約 10(重い裾)
東京の人口:d[d.都道府県=='東京都'].総人口.iloc[0] → 14086000
神奈川:9229000
大阪:8763000
愛知:7477000
埼玉:7331000
千葉:6257000
兵庫:5370000
福岡:5103000
北海道:5092000
静岡:3555000
茨城:2840000
広島:2738000
京都:2522000
宮城:2266000
新潟:2126000
長野:2010000
岐阜:1931000
群馬:1903000
栃木:1897000
岡山:1839000
福島:1767000
三重:1727000
熊本:1707000
鹿児島:1547000
沖縄:1468000
滋賀:1399000
山口:1294000
愛媛:1291000
奈良:1296000
長崎:1267000
青森:1184000
岩手:1163000
大分:1096000
石川:1109000
宮崎:1052000
山形:1026000
富山:1003000
香川:926000
秋田:920000
和歌山:892000
山梨:796000
佐賀:795000
福井:744000
徳島:695000
高知:667000
島根:651000
鳥取:537000
出生数全国合計:d['出生数'].sum() → 727,269
東京都の出生数:86,348
合計特殊出生率 TOP は沖縄県の 1.60
合計特殊出生率 LAST は東京都の 0.99(唯一 1.0 未満)
東京都の婚姻件数:71,774 件
東京都の離婚件数:20,016 件
離婚率(離婚÷婚姻):71774/160732 → 44.7%
東京都の年平均気温:17.6°C
沖縄県の年平均気温:最高クラス 23°C 台
北海道の年平均気温:11.0°C(最低)
2012-2023 全国総人口の変化:減少傾向
東京都 2012:13,234,000 人
東京都 2023:14,086,000 人
東京都 12 年増加:+890,000 人
東京都年率:+0.55%
東京都の前年差 2020→2021:-38,000 人(コロナ)
大阪府 2012:8,861,000 → 2023:8,763,000、 -98,000 人(減少)
沖縄県 2012:1,411,000 → 2023:1,468,000、 +57,000 人(増加)
鳥取県 2012:583,000 → 2023:537,000、 -46,000 人
秋田県 2012:1,063,000 → 2023:914,000、 -149,000 人
北海道 2012 → 2023:-373,000 人
関東 7 都県合計 2023:43,495,000 人
近畿 7 府県合計 2023:22,031,000 人
中部 9 県合計 2023:20,758,000 人
九州沖縄 8 県合計 2023:12,914,000 人
東北 6 県合計 2023:8,425,000 人
中国 5 県合計 2023:7,071,000 人
四国 4 県合計 2023:3,594,000 人
北海道 1 道:5,092,000 人
関東のシェア:43.5M / 124.4M = 35.0%
東京都のシェア:14.1M / 124.4M = 11.3%
1 都 3 県(東京・神奈川・千葉・埼玉)シェア:30%
大阪府の出生率:1.19
愛知県の出生率:1.29
福岡県の出生率:1.26
合計特殊出生率全国(2023):約 1.20
人口置換水準 2.07 を満たす県:ゼロ
少子化が最も進行:東京都(0.99)
「主キー」関連の数値感:1 都道府県 ≒ 100 万〜1500 万人
「主キー」を語る基礎データ:47 県 × 12 年 × 112 列
「主キー」を CC BY 4.0 で誰でも自由に教材化可能
「主キー」x SSDSE-B-2026:ジャストインタイム型教育の理想素材
🎓 「主キー」は SSDSE-B-2026 で「触って学ぶ」のが最短ルート
🔑 「主キー」を題材にした実践ノートブック構成例
Cell 1:Import + データロード + 出典明記
Cell 2:基本統計(describe)
Cell 3:欠損値確認
Cell 4:「主キー」関連列の抽出
Cell 5:可視化(matplotlib / seaborn)
Cell 6:仮説の数式化
Cell 7:「主キー」を用いた計算実装
Cell 8:結果の数値解釈
Cell 9:限界・前提条件の議論
Cell 10:再現性(出典・ライセンス・コード)
🔑 SSDSE-B-2026 解析で頻出する Python パターン 30 個
# パターン 用途
1 df.head()先頭 5 行確認
2 df.info()列型・欠損確認
3 df.describe()記述統計
4 df.isnull().sum()欠損値カウント
5 df[df.年度==2023]年度フィルタ
6 df.nlargest(5, '総人口')TOP 5
7 df.nsmallest(5, '総人口')BOTTOM 5
8 df.groupby('都道府県')['総人口'].mean()県別平均
9 df.pivot_table(...)クロス集計
10 df.diff()前年差
11 df.pct_change()変化率
12 df.rolling(3).mean()移動平均
13 df.cumsum()累積和
14 df.corr()相関行列
15 df.melt()Wide → Long
16 df.merge()結合
17 df.set_index()インデックス設定
18 df.sort_values()並び替え
19 df.to_csv()CSV 出力
20 df.to_parquet()Parquet 出力
21 df.apply(func, axis=1)行ごと関数適用
22 df.iloc[i]位置アクセス
23 df.loc[mask]条件アクセス
24 df.shape行列数
25 df.columns列名一覧
26 df.dtypes列型一覧
27 df.value_counts()値の度数
28 df.dropna()欠損行除去
29 df.fillna(0)欠損埋め
30 df.astype(int)型変換
🔑 「主キー」を学ぶ際の参考文献 + Web リソース
分野標準教科書(学術書、 数千ページレベル)
Python ライブラリ公式ドキュメント(pandas、 NumPy、 scikit-learn)
Real Python、 Towards Data Science、 Kaggle Learn
独立行政法人統計センター SSDSE-B-2026(CC BY 4.0)
e-Stat 政府統計の総合窓口(出典・データ源)
RESAS 地域経済分析システム
World Bank Open Data(国際比較)
arXiv(最新研究論文)
GitHub Awesome リスト(分野別の優れた資料集)
YouTube 講義(3Blue1Brown、 StatQuest、 Two Minute Papers)
🔑 最終確認:「主キー」を SSDSE-B-2026 で完全に学べたか?
SSDSE-B-2026 を CC BY 4.0 で読み込み、 出典明記したか?
47 都道府県・12 年の数値感覚を得たか?
「主キー」を 3 行 Python で実装できるか?
東京都 14,086,000 人・鳥取県 537,000 人・26 倍格差を覚えたか?
合計特殊出生率の沖縄 1.60、 東京 0.99 を覚えたか?
「主キー」を 5 分プレゼンで他者に説明できるか?
「主キー」の落とし穴を 3 つ挙げられるか?
分析結果を出典明記のレポートに仕上げられるか?
これら 8 項目すべてが ✅ なら、 SSDSE-B-2026 を題材にした「主キー」の習得は完了です。 次の用語・次の分野へ進みましょう。
🌟 SSDSE-B-2026 ハンズオン総合演習:「主キー」テーマで 1 時間プロジェクト
🔑 プロジェクト概要
「主キー」を題材に、 SSDSE-B-2026 を使った 1 時間完結のミニプロジェクトを構築する手順。 ジャストインタイム型学習の「実際にやってみる」フェーズの実装版です。
🔑 タイムテーブル
時間 作業 具体的内容
0-10 分 環境準備 Jupyter 起動、 SSDSE-B-2026 ロード、 head/describe
10-20 分 「主キー」関連列特定 112 列から関連する列を 5〜10 個選別
20-30 分 探索的データ分析 箱ひげ図、 散布図、 相関行列
30-45 分 「主キー」を用いた分析 仮説立て、 計算、 結果数値化
45-55 分 レポート作成 Markdown / HTML で結果まとめ、 出典明記
55-60 分 振り返り 限界・次のステップ・他者共有準備
🔑 アウトプット例
1 時間後にあなたが持つもの:
Jupyter Notebook 1 つ(再現可能、 50〜100 セル)
Markdown レポート(A4 換算 2〜3 枚)
可視化 PNG 3〜5 枚
派生 CSV / Parquet ファイル
LICENSE.txt(CC BY 4.0、 出典明記)
GitHub 公開可能なコード一式
🔑 次のステップ
このノートを「主キー」を学ぶ仲間と共有
SSDSE-B-2026 以外のデータ(SSDSE-A、 e-Stat 別系)でも同じ分析を試す
「主キー」の前提・並列・発展用語をマスター
関連分野の論文・書籍を 1 冊読む
学んだ内容をブログ or 勉強会で発表
📘 「主キー」(Primary Key) 上級アペンディックス — 47 都道府県全データで読み解く完全ガイド
🔑 47 都道府県の総人口 + 出生数 + 出生率の完全テーブル(2023 年)
順位 都道府県 地域コード 総人口 出生数 合計特殊出生率 地方
1 東京都 R13000 14,086,000 86,348 0.99 関東
2 神奈川県 R14000 9,229,000 53,991 1.13 関東
3 大阪府 R27000 8,763,000 55,292 1.19 近畿
4 愛知県 R23000 7,477,000 48,402 1.29 中部
5 埼玉県 R11000 7,331,000 42,108 1.14 関東
6 千葉県 R12000 6,257,000 35,658 1.14 関東
7 兵庫県 R28000 5,370,000 32,615 1.29 近畿
8 福岡県 R40000 5,103,000 33,942 1.26 九州
9 北海道 R01000 5,092,000 24,430 1.06 北海道
10 静岡県 R22000 3,555,000 18,969 1.25 中部
11 茨城県 R08000 2,840,000 15,800 1.27 関東
12 広島県 R34000 2,738,000 16,600 1.36 中国
13 京都府 R26000 2,522,000 14,300 1.14 近畿
14 宮城県 R04000 2,266,000 12,100 1.15 東北
15 新潟県 R15000 2,126,000 10,500 1.27 中部
16 長野県 R20000 2,010,000 10,700 1.38 中部
17 岐阜県 R21000 1,931,000 10,400 1.33 中部
18 群馬県 R10000 1,903,000 10,000 1.32 関東
19 栃木県 R09000 1,897,000 10,100 1.27 関東
20 岡山県 R33000 1,839,000 10,400 1.39 中国
21 福島県 R07000 1,767,000 9,400 1.27 東北
22 三重県 R24000 1,727,000 9,500 1.34 近畿
23 熊本県 R43000 1,707,000 11,000 1.43 九州
24 鹿児島県 R46000 1,547,000 9,400 1.44 九州
25 沖縄県 R47000 1,468,000 11,816 1.60 九州
26 滋賀県 R25000 1,399,000 8,500 1.43 近畿
27 奈良県 R29000 1,296,000 6,700 1.16 近畿
28 山口県 R35000 1,294,000 6,900 1.40 中国
29 愛媛県 R38000 1,291,000 6,700 1.36 四国
30 長崎県 R42000 1,267,000 7,300 1.45 九州
31 青森県 R02000 1,184,000 5,400 1.24 東北
32 岩手県 R03000 1,163,000 5,600 1.21 東北
33 石川県 R17000 1,109,000 6,300 1.38 中部
34 大分県 R44000 1,096,000 6,300 1.40 九州
35 宮崎県 R45000 1,052,000 6,800 1.49 九州
36 山形県 R06000 1,026,000 5,000 1.32 東北
37 富山県 R16000 1,003,000 5,200 1.36 中部
38 香川県 R37000 926,000 5,400 1.42 四国
39 秋田県 R05000 920,000 3,700 1.18 東北
40 和歌山県 R30000 892,000 4,500 1.40 近畿
41 山梨県 R19000 796,000 4,300 1.41 中部
42 佐賀県 R41000 795,000 5,000 1.46 九州
43 福井県 R18000 744,000 4,500 1.47 中部
44 徳島県 R36000 695,000 3,500 1.34 四国
45 高知県 R39000 667,000 3,400 1.35 四国
46 島根県 R32000 651,000 4,200 1.45 中国
47 鳥取県 R31000 537,000 3,739 1.46 中国
🔑 この表から「主キー」視点で読み取れる 10 の発見
東京都の異常値性 :14.1M で 2 位の神奈川(9.2M)に大差。 統計学的外れ値
26 倍の格差 :東京 14M vs 鳥取 0.54M。 47 都道府県という単位の異質性
合計特殊出生率の地方圏優位 :沖縄 1.60、 宮崎 1.49、 鳥取 1.46。 大都市ほど低い
東京都の出生率 0.99 :47 県中唯一 1.0 を割り、 「都市集中 = 少子化加速」を象徴
地方ブロック差 :関東 43.5M、 近畿 22.0M、 中部 20.8M で上位 3 ブロック合計 86.3M(全国の 68%)
東北 6 県合計 8.4M :神奈川県 1 県(9.2M)以下
九州沖縄 8 県合計 12.9M :埼玉県 + 千葉県程度
四国 4 県合計 3.6M :静岡県 1 県と同等
地域コード規則性 :R01 北海道 → R47 沖縄、 ほぼ北から南へ
出生数 86k 〜 3.7k :23 倍の格差、 出生率の地方優位を打ち消す絶対数の集中
🔑 「主キー」の議論で使える数値レパートリー
全国合計 2023 :124,353,000 人
平均 / 中央値 :2,690,000 / 1,839,000 人
標準偏差 :2,627,921(平均とほぼ同等、 ばらつき極大)
歪度 :約 +3.0(強い右歪み、 東京が引っ張る)
1 都 3 県シェア :30% 強
太平洋ベルト(東京〜大阪 + 名古屋)シェア :50% 超
出生数全国 2023 :727,269 人(戦後最少水準)
婚姻件数全国 :474,741 件
離婚件数全国 :183,814 件
婚姻 → 離婚率 :約 41%
🔑 SSDSE-B-2026 で「主キー」を可視化するためのコード
🎯 やること :47 都道府県の総人口と合計特殊出生率を散布図で可視化、 東京都が「規模が大きく出生率が低い」極端点であることを視覚的に確認。
📥 入力 :SSDSE-B-2026 の 2023 年データ 47 行。
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 import pandas as pd
import matplotlib.pyplot as plt
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = 1 )
d = df [ df [ '年度' ] == 2023 ]
fig , ax = plt . subplots ( figsize = ( 10 , 6 ))
ax . scatter ( d [ '総人口' ] / 1e6 , d [ '合計特殊出生率' ], s = 50 , alpha = 0.6 )
# 主要 5 県のラベル付け
highlights = [ '東京都' , '神奈川県' , '大阪府' , '沖縄県' , '鳥取県' ]
for _ , row in d . iterrows ():
if row [ '都道府県' ] in highlights :
ax . annotate ( row [ '都道府県' ],
( row [ '総人口' ] / 1e6 , row [ '合計特殊出生率' ]),
fontsize = 10 , ha = 'left' , va = 'bottom' )
ax . set_xlabel ( '総人口(百万人)' )
ax . set_ylabel ( '合計特殊出生率' )
ax . set_title ( '47 都道府県:人口規模 vs 合計特殊出生率(2023) \n 出典: SSDSE-B-2026 (CC BY 4.0)' )
ax . axhline ( y = 2.07 , color = 'red' , linestyle = '--' , alpha = 0.5 , label = '人口置換水準 2.07' )
ax . legend ()
ax . grid ( alpha = 0.3 )
plt . tight_layout ()
plt . savefig ( 'scatter.png' , dpi = 150 )
print ( "散布図保存完了" )
📤 出力(散布図のイメージ) :
散布図保存完了
特徴:
- 横軸 0.5〜14 百万人、 縦軸 0.99〜1.60
- 東京都が右下(人口最大・出生率最低)の極端点
- 沖縄県・鳥取県が左上(小規模・高出生率)
- 多くの県は 1〜3 百万人 × 1.2〜1.5 のクラスタ
- 人口置換水準 2.07 はどの県も到達せず
💬 解説 :散布図から「人口規模が大きい県ほど出生率が低い」という負の相関(r ≈ -0.34)が一目で分かる。 東京都の異常性が際立つ。 「主キー」の議論でこの 1 枚を提示するだけで、 都市集中と少子化の関連を雄弁に語れる。
🔑 「主キー」のさらなる学びへの 10 のリンク先
独立行政法人統計センター SSDSE 公式ページ
e-Stat(政府統計の総合窓口)
RESAS(地域経済分析システム)
OECD Data Portal(国際比較)
World Bank Open Data
分野標準学会・ジャーナルのオープンアクセス論文
Coursera / edX / Udemy の関連オンラインコース
Kaggle のデータセットとノートブック
GitHub の関連 OSS プロジェクト
arXiv の最新研究プレプリント
🔑 「主キー」を学んだ後のキャリア・成長パス
データアナリスト :SSDSE-B-2026 のような公的統計を扱う実務
データサイエンティスト :「主キー」を含む高度分析手法を駆使
MLE / AI エンジニア :「主キー」を機械学習システムに組込み
BI コンサルタント :データを使ったビジネス提案
研究者 :「主キー」を発展させる学術研究
教育者 :他者に「主キー」を教える
政策立案者 :SSDSE-B-2026 を地域政策に活用
起業家 :「主キー」を活用したサービス開発
📕 「主キー」上級者向け SSDSE-B-2026 完全分析カタログ
🔑 12 年トレンド:全国総人口推移と「主キー」
年 全国総人口 前年差 出生数 合計特殊出生率(全国)
2012 約 127,589,000 — 約 1,037,000 1.41
2013 約 127,414,000 -175,000 約 1,030,000 1.43
2014 約 127,238,000 -176,000 約 1,004,000 1.42
2015 約 127,095,000 -143,000 約 1,006,000 1.45
2016 約 127,044,000 -51,000 約 977,000 1.44
2017 約 126,920,000 -124,000 約 946,000 1.43
2018 約 126,748,000 -172,000 約 918,000 1.42
2019 約 126,555,000 -193,000 約 865,000 1.36
2020 約 126,146,000 -409,000 約 841,000 1.33
2021 約 125,500,000 -646,000 約 812,000 1.30
2022 約 124,946,000 -554,000 約 771,000 1.26
2023 約 124,353,000 -593,000 727,269 1.20
🔑 47 都道府県の「12 年間人口変化」
2012→2023 で人口が増加した都道府県(7 県):
都道府県 2012 2023 増加 年率
東京都 13,234,000 14,086,000 +852,000 +0.57%
神奈川県 9,070,000 9,229,000 +159,000 +0.16%
埼玉県 7,216,000 7,331,000 +115,000 +0.14%
沖縄県 1,411,000 1,468,000 +57,000 +0.36%
千葉県 6,200,000 6,257,000 +57,000 +0.08%
愛知県 7,431,000 7,477,000 +46,000 +0.06%
福岡県 5,089,000 5,103,000 +14,000 +0.02%
📝 より正確な分析 :実データ(SSDSE-B-2026、2012→2023)で再集計すると、人口が増加したのは 7 県 (東京・神奈川・埼玉・沖縄・千葉・愛知・福岡)。旧版で「5 県のみ」としていたのは千葉・福岡を取りこぼした集計。
2012→2023 で人口が減少した県の TOP 5(年率順):
都道府県 2012 2023 減少 年率
秋田県 1,063,000 914,000 -149,000 -1.36%
青森県 1,350,000 1,184,000 -166,000 -1.19%
高知県 751,000 666,000 -85,000 -1.09%
山形県 1,153,000 1,026,000 -127,000 -1.06%
岩手県 1,306,000 1,163,000 -143,000 -1.05%
🔑 「主キー」を SSDSE-B-2026 で深掘りする 30 の発展タスク
SSDSE-B-2026 を SQLite にロードし、 「主キー」に関連する SQL クエリを 10 個書く
matplotlib + seaborn で「主キー」可視化を 5 枚作成
scikit-learn の RandomForest で都道府県分類モデルを学習
statsmodels で回帰分析、 係数の解釈
scipy.stats で正規性検定(Shapiro-Wilk、 Kolmogorov-Smirnov)
仮説検定:「都市部と地方部で「主キー」関連指標に有意差があるか」
線形混合効果モデルで都道府県・年度の二重階層を考慮
時系列分析(ARIMA、 Prophet)で人口推移を予測
PCA で 112 列を 2 次元に圧縮、 都道府県を可視化
t-SNE / UMAP で非線形次元削減を試す
K-means で都道府県を 5 群にクラスタリング
階層クラスタリング(ward 法)でデンドログラム作成
DBSCAN で密度ベースクラスタリング
因子分析で潜在変数を抽出
因果推論:DiD(差分の差分)で施策効果を測定
ベイズ推定(PyMC)で都道府県別パラメータを階層的に推定
Streamlit で「主キー」可視化ダッシュボードを構築
Dash でインタラクティブ可視化
FastAPI で「主キー」分析 API を公開
Jupyter Book でドキュメント化、 GitHub Pages で公開
Docker コンテナ化、 再現可能な分析環境構築
Snakemake / Nextflow で分析パイプライン自動化
MLflow で実験管理
DuckDB で SSDSE-B-2026 を高速集計
Polars で大規模データ処理の練習
PyTorch / JAX で「主キー」関連モデル実装
HuggingFace で SSDSE-B-2026 を Dataset 化、 公開
OpenAI API で SSDSE-B Q&A BOT 構築
LangChain で SSDSE-B-2026 RAG パイプライン
📝 ブログ・論文として成果を公開、 出典明記(CC BY 4.0)
🔑 「主キー」研究・実務の最前線リソース
arXiv の関連プレプリント(毎月最新)
NeurIPS / ICML / ICLR / KDD などの主要会議
Google Scholar アラート設定(キーワード「主キー」)
Twitter / X の研究者アカウント追跡
Hacker News、 Reddit r/datascience、 r/machinelearning
Medium、 Towards Data Science、 Distill の解説記事
GitHub Trending の関連リポジトリ
Kaggle Competitions の上位解法
Coursera Specialization、 fast.ai コース
日本ソフトウェア科学会、 統計数理研究所のセミナー
🔑 「主キー」と SSDSE-B-2026 から派生する研究テーマ案
「主キー」を用いた 47 都道府県の類型化と政策示唆
SSDSE-B-2026 と気象データを統合した「主キー」分析
「主キー」と地方自治体の財政指標の関係
SSDSE-B-2026 で見る「主キー」の地域格差動態
「主キー」の時系列予測と政策評価
SSDSE-B-2026 + 国勢調査の統合解析
「主キー」を用いた将来人口シナリオ分析
SSDSE-B-2026 と SNS データのクロス解析
「主キー」の都道府県別効率性フロンティア(DEA)
SSDSE-B-2026 を題材とした「主キー」教育プログラム開発
🔑 最後に:「主キー」を 1 行で説明できますか?
このページを最後まで読んだ皆さんへの最終チェック:「主キー」を 30 字以内で説明してみてください。 もしできなかったら、 もう一度「直感で掴む」セクションに戻って読み直しましょう。 ジャストインタイム型学習は「行きつ戻りつ」 が真髄。 完璧な理解より、 必要なときに必要な深さで「使える」ことが目標です。
そして、 学んだ「主キー」を SSDSE-B-2026 で実証し、 他者に伝えることで、 知識は本当の意味で「自分のもの」になります。 教えることが最良の学びです。
— 「主キー」を学ぶあなたへ、 SSDSE-B-2026 と共に。
🗺 概念マップ
主キー (Primary Key) を中心に、 上位概念 (RDB スキーマ設計・関係モデル)、 並列概念 (外部キー・候補キー・代理キー・複合キー)、 制約 (一意性 + 非 NULL + 不変性)、 応用 (JOIN・正規化・SSDSE-B の SSDSE-2026 列など) を関係づけて整理する。
primary key
外部キー (Foreign
候補キー (Candidat
スーパーキー
UUID / ULID /
クラスタリングインデックス
落とし穴
主キー (primary key) はリレーショナルデータベースで「行を一意に特定する 1 列または列の組合せ」で、 NOT NULL かつ UNIQUE 制約が強制される。 SSDSE-B-2026 では「SSDSE-2026 + 都道府県コード」が複合主キーに相当し、 これによって「同じ都道府県の同じ年のレコードは 1 つだけ」が保証される。 自然キー (意味のある値)・代理キー (UUID/ULID/連番) のどちらを使うか、 クラスタリングインデックスとして物理配置を決めるかなどの設計判断が、 後の JOIN 性能・データ統合・落とし穴の発生確率に直結する。
🔗 隣接手法への橋渡し
主キーは「テーブル設計 → データ整合性 → 分析」の連鎖で中心的な役割を果たし、 隣接する DB 設計概念と密接に絡む。
上流(DB 設計) : ER 図 でエンティティを定義し、 正規化 でテーブルを分割する際、 各テーブルに必ず主キーを定める。 候補キーから 1 つ選んだものが主キーになる。
並列(同じ「一意性保証」) : UNIQUE 制約 は主キー以外の列にも一意性を要求 (NULL は許容)、 外部キー は別テーブルの主キーを参照する整合性の鎖、 複合キー は複数列で 1 つの主キーを構成する変種。
下流(分析と統合) : JOIN で複数テーブルを結合する際の連結軸、 pandas.merge の on= パラメータも主キー対応列を指定、 データ統合 で異なるシステム間の同一エンティティを突合する基準。
主キーが設計されていないテーブルは「重複行が混入する」「JOIN 結果が膨らむ」「集計値が二重計上される」という致命的な分析バグを生み、 SSDSE-B-2026 のような分析用データセットでも (都道府県, 年) の組が暗黙の主キーとして扱われている。
🌳 手法選択フロー
「主キー」を実際に使うとき、 何をどう選ぶかを順に判断する。 上から順に答えていくと、 使うべき手法と評価の仕方が決まる。
1 列で行を一意に決められるか 決められるなら単一キー。 SSDSE-B-2026 では地域コードの一意数が 47 しかなく、 564 行を識別できない。 決められないなら複合キーへ。
複数列の組で一意になるか 地域コード + 年度の 2 列なら、 組の一意数が 564 となり全行を識別できる(実測)。 組にしても重複が残るなら、 データの粒度の理解が間違っている。
自然キーか、 代理キーか 地域コードのように意味を持つ列は、 市町村合併などで値が変わりうる。 変更に弱いなら意味のない連番(代理キー)を立て、 自然キーには一意制約を付ける。 外部キー から参照する側も単純になる。
NULL を許すか 主キーは NULL を取れない。 未確定の値がある列は主キーにできないので、 候補から外すか、 確定するまで代理キーで運用する。
SSDSE-B-2026 は 47 県 × 12 年度 = 564 行。 「地域コードが主キー」と決めつけると 1 県あたり 12 行が重複扱いになり、 結合で行数が 12 倍に膨らむ。
❌ 自然キーを安易に選ぶ
メールアドレスや電話番号を主キーにすると、 ユーザーが変更したときに全関連テーブルを更新する大工事に。
❌ 複合キーの罠
便利だが、 外部キーから参照する側も複合になり JOIN が複雑化。 代理キーのほうが楽な場合多し。
❌ UUID の性能
UUID は分散システムに便利だが、 B-Tree インデックスでランダム挿入 → ページ分裂で遅くなる。 ULID 等を検討。
❌ NULL 許容に変更
後から主キー列を NULL 許容にすることは原理的に不可能。 設計時に確定を。
❌ ビジネスロジック混入
「ID の最初の桁が地域コード」のように主キーに意味を持たせると、 再編時に詰む。 主キーは単純に。
💥 主キーに NULL を許す
「都道府県 単独で PK」だと未登録が発生し NULL 混入、 一意性破綻。 NOT NULL を必ず指定。
💥 PK を後から変更
PK は外部キー(FK)で参照される。 変更すると参照側も書き換え必要。 SSDSE-B では「年度 4 桁 → 6 桁」化など。
💥 PK に意味付け
「東京都の id は必ず 1 番」という決め打ちは将来の拡張で破綻。 代理キーは「意味なし」が原則。
💥 UUID 主キーで INSERT 性能低下
B-tree インデックスはランダム UUID で局所性が悪化、 INSERT が 5〜10 倍遅くなることも。 ULID や Snowflake ID を選ぶ。
💥 重複データの PK 衝突
SSDSE-B-2026 を 2 回ロードすると UNIQUE constraint failed。 INSERT OR REPLACE や ON CONFLICT 句で対応。
📜 ひとことヒストリー
主キー は「データエンジニアリング」分野の中で発展してきた概念・手法です。 学術的には継続的な研究で精緻化され、 実務的にはツール・ライブラリの普及で誰でも使えるようになってきました。 用語の使い方・意味は時代と分野で少しずつ変わるため、 文脈に応じた解釈が大切です。 入門書だけでなく、 標準的な教科書(例:データサイエンス・統計学の定本)や信頼できるオンライン教材も併用すると、 ぶれない理解に近づけます。
✅ 実務チェックリスト — 主キー
□ 用語の定義を自分の言葉で説明できるか
□ 使うべき場面と使ってはいけない場面を区別できているか
□ 数式や指標の前提条件を確認したか
□ 入力データの尺度・分布・サンプル数を確認したか
□ 結果の不確実性(信頼区間・標準誤差)を把握しているか
□ 解釈と限界を区別できているか
□ 関連用語・落とし穴を一通り点検したか
□ レポートに必要な情報(出典・前提・限界)を含められるか
🎯 まとめ — このページで押さえること
「主キー」 はこのページで詳しく扱った概念です。 持ち帰ってほしい 3 つの要点 :
主キー(Primary Key) =テーブル内で 各行を一意に識別 する列(または列の組合せ)。条件:(1) 一意 、 (2) NULL 不可 、 (3) 不変 (できれば)。 自然キー (マイナンバー等の実在 ID)vs 代理キー (システム生成の連番/UUID)。 代理キー推奨。
さらに学ぶには、 関連用語 や 関連グループ教材 を参照してください。 各用語ページを縦断的に読むことで、 体系的な理解が育ちます。
🎮 触って理解する — 主キー診断ラボ
下の架空のサンプル名簿 (氏名・メール等はすべて作例)で、列見出しをタップ/クリック して主キー候補に指定してみてください。複数の列を選ぶと複合キー になります。選んだ瞬間に「一意性チェック(重複=赤 )」と「NULL チェック(オレンジ )」が走り、主キーとして妥当かが即座に判定されます。
クイック選択:
ID(代理キー)
氏名
メール
生年月日
氏名+生年月日(複合)
全解除
判定待ち…
➕ 行を追加(ID 自動採番)
💥 重複 ID=1 で追加を試す
🕳 ID なし(NULL)で追加を試す
↺ リセット
一意性の判定式:選択キーの「異なり値の数」=「行数」かつ NULL 数 = 0 のとき合格。下の図は操作に合わせてリアルタイム更新されます。
行数
0
異なり値の数
-
NULL 行数
-
キー未選択
列見出しをタップしてください
🧭 遊び方のヒント(この順に試すと全パターン体験できます)
氏名 だけを選ぶ → 「佐藤 陽菜」が 2 人いて赤くハイライト。同姓同名で失格 。
メール → 値自体は重複しないが NULL(未登録)が 1 件。NULL があれば主キー失格 。
生年月日 → 2005-11-03 生まれが 2 人。日付は簡単に衝突する。
氏名+生年月日 の 2 列 → 単独では失格だった列も、組合せなら全行一意 になり合格(複合キーの体験)。
ID → 単独で合格。これが代理キー(連番) 。「行を追加」を何回押しても自動採番で衝突しない。
ID を主キーにした状態で「重複 ID=1 で追加 」→ UNIQUE 制約エラーで弾かれ、衝突行が点滅。「ID なしで追加 」→ NOT NULL 制約エラー。
全解除 してから「重複 ID=1 で追加」→ 誰も止めずに入ってしまう。主キーが無いテーブルの危うさ を体感。
💡 直感 — 主キーは「背番号」
主キーは行を一意に特定する背番号 です。名前で選手を呼ぶと同姓同名で混乱しますが、背番号で呼べば必ず 1 人に届く。上のデモで「氏名」が赤くなるのはまさにこの混乱で、データベースは「どちらの佐藤 陽菜さんですか?」に答えられなくなります。さらに背番号は空欄不可 (NULL は「不明」を意味し、不明どうしは等しいとも等しくないとも言えないため比較が破綻する)、シーズン途中で変えない (不変性)——この 3 点セットが主キーの要件です。
⚠️ よくある落とし穴 — デモで起きたことの一般化
「今たまたま一意」を「主キーにできる」と誤解する :デモの初期 5 行では「メール(NULL を除けば)」も一意に見えますが、一意性は将来の挿入も含めて保証すべき性質 。行を追加していくと自然キーはいつか衝突します。
自然キーの変化 :メールアドレスは機種変更・卒業で変わり、氏名は改姓で変わります。主キーが変わると、それを参照する全テーブルの外部キーを更新する大工事に。
氏名・日付をキーにする危険 :同姓同名(デモの佐藤 陽菜)や同一生年月日(デモの 2005-11-03)は現実に高頻度で発生。氏名は表記揺れ(全角/半角スペース、旧字体)でも別値扱いになり、結合ズレの温床になります。
NULL の見落とし :UNIQUE 制約は NULL を複数許す実装が多い(SQL 標準では NULL どうしは「等しい」と判定されない)ため、「UNIQUE だから主キーにできる」は誤り。主キーは UNIQUE + NOT NULL の両方が必要です(欠損値 も参照)。
🚀 発展 — 複合キー・代理キー・外部キーとのつながり
複合キー :デモの「氏名+生年月日」のように、単独では一意にならない列も組合せで一意になれます。本ページで扱った SSDSE-B-2026 の (年度, 地域コード) (47 都道府県 × 2012〜2023 年の 12 年 = 564 行)が実データでの典型例。ただし列が増えるほど外部キー側も複合になり JOIN が複雑化します(テーブル結合 )。
代理キー vs 自然キー :デモの ID 列のようにシステムが採番する連番/UUID が代理キー。値に意味が無いからこそ変更理由が発生せず安定 します。自然キー(メール、マイナンバー、ISBN)は人間に読みやすい反面、変更・再利用・桁数改定のリスクを抱えます。実務では「代理キーを主キーに、自然キーには UNIQUE 制約を」が定石。
外部キーとの関係 :主キーは外部キー から参照されることで初めてリレーショナル DB(RDB )の力を発揮します。参照整合性(存在しない主キー値を指す外部キーを拒否する仕組み、完全性 )の土台であり、テーブル設計全体は ER 図 で俯瞰できます。主キー制約の宣言方法は DDL (CREATE TABLE の PRIMARY KEY 句)を参照してください。
🔎 解説深化 — 「たまたま一意」と「設計上一意」を実データで見分ける
ここまでのセクションで主キーの 3 要件(一意・非 NULL・不変)と複合キー (年度, 地域コード) の設計を学びました。 この深化セクションでは一歩進めて、 「観測された一意性」と「設計として保証された一意性」はまったく別物である ことを、 SSDSE-B-2026 の実測値で定量的に確かめます。 これは上の診断ラボ(架空名簿)で体験した「今たまたま一意」問題の、 実データ版・統計版 です。
💡 直感 — 一意性は「観測」ではなく「約束」
SSDSE-B-2026 の 2023 年断面(47 都道府県 = 47 行)で、 年度・地域コード・都道府県名を除く数値 109 列 それぞれの「異なり値の数」を数えると、 実に 74 列(約 67.9%)が nunique = 47 、 つまりその瞬間だけ見れば全行一意 です。 総人口(A1101)も 47 通りで完全に一意。 では「総人口を主キーにできる」でしょうか?
答えは No。 断面を 2012〜2023 年の全パネル 564 行に広げると、 総人口の異なり値は 520 に減り、 44 行 が他の行と値を共有します。 実際の衝突例(すべて実測):
2023 年の福井県 と2017 年の徳島県 :どちらも総人口 744,000 人 。 県も年も違うのに値が同じ。
2023 年の秋田県 と2021 年の和歌山県 :どちらも 914,000 人 。
滋賀県 は 2012・2014・2016・2017・2018 年の 5 か年 が同じ 1,414,000 人 (千人単位への丸めの影響)。 沖縄県も 2021〜2023 年の 3 か年が 1,468,000 人で並びます。
主要列の「断面 vs パネル」一意性を並べると、 観測一意性がいかに脆いかが分かります:
列 2023 年断面の異なり値 (47 行中) パネル全体の異なり値 (564 行中) 判定
Code(地域コード) 47 47 断面ではキー、 パネルでは 12 重に重複
A1101 総人口 47 520 偶然の一意性。 キー不適
B4101 年平均気温 31 101 断面ですら 16 組が衝突
A4103 合計特殊出生率 31 82 桁が粗く衝突多発
E6101 短期大学数 16 36 「5 校」が 8 県で同値
(年度, Code) 複合 47 564 設計上のキー。 全行一意
つまり主キーとは「手元のデータで重複が無かった」という観測報告 ではなく、 「将来追加される行も含めて、 DB が衝突を拒否し続ける 」という約束(制約) です。 観測はいくらでも裏切られますが、 約束はスキーマが守ります。
⚠️ 落とし穴(重要)
「nunique == 行数」検査の合格をキー認定と混同する :df['A1101'].nunique() == len(df) は 2023 年断面なら True です。 しかしこの検査は一意性の必要条件 を確認しただけで、 十分条件 ではありません。 翌年分を concat した瞬間に崩壊し得ます(実際、 総人口は 564 行に広げると 44 行が衝突)。 キーの資格は「その列の値が何を識別する意図で振られたか 」という意味論で決めるべきものです。
丸められた統計値は衝突しやすい :SSDSE-B の総人口は千人単位に丸められているため、 滋賀県のように 5 か年連続同値が起こります。 合計特殊出生率(小数 2 桁)に至っては 2023 年の 47 都道府県で 31 種類 しか値が無く、 埼玉県と千葉県が 1.14、 栃木県と大阪府が 1.19 で衝突。 有効桁が少ない列ほど「値の空間 N」が小さくなり衝突確率が跳ね上がる—— これは上の計算例セクション で見た誕生日問題と同じ構造です。 「測定値・集計値は原理的にキーになれない」と覚えてください。
逆パターン:本物のキーが重複して見えたらデータ汚染を疑う :df.duplicated(subset=['SSDSE-B-2026','Code']).sum() は現在の SSDSE-B-2026 で 0 (実測)。 もしこれが 0 でなくなったら、 それはキー設計の誤りではなく二重ロードや結合ミスの検出器が鳴った ということです。 pandas には SQL の PRIMARY KEY 制約が無いので、 set_index([...], verify_integrity=True) や merge(..., validate='one_to_one') を ETL の各段に置いて、 約束を手動で検査し続ける必要があります。
🚀 発展 — キー発見(key discovery)という研究分野
「ドキュメントの無い未知のテーブルから候補キーを自動で見つける」問題は、 データプロファイリング研究でキー発見・関数従属発見 と呼ばれる一分野です(代表的アルゴリズムに TANE や HyFD)。 列の組合せは $2^{n}$ 通りに爆発するため、 単独列 → 2 列 → 3 列と段階的に持ち上げる格子(lattice)探索 と枝刈りが使われます。 SSDSE-B-2026 は 112 列なので全探索は $2^{112}$ 通り—— 現実には「一意率 = nunique / 行数」が高い列から優先的に組合せる、 という発想が要になります(実測:Code の一意率は 47/564 ≈ 0.083、 (年度, Code) で 1.0 に到達)。
もう 1 つの発展は「不変のはずのキーが変わる」問題 です。 都道府県コードは長期に安定した良質な自然キーですが、 市町村コードは平成の大合併期に大量に改番されました。 時系列データでキーの対応関係そのものが変化する場合の管理手法は、 データウェアハウス分野で Slowly Changing Dimension(SCD) として体系化されています。 「主キーの不変性」は無料で手に入る性質ではなく、 コード表の版管理という運用努力の産物です。
外部キー — 主キーを参照して参照整合性を築く相方。 完全性 とセットで。
テーブル結合 — 「キーの一意性検査(validate 引数)」が最も効く実践の場。
パネルデータ — 本ページの (年度, 地域コード) 複合キーはパネルデータ構造そのもの。
欠損値 — NULL がキーに混ざるとなぜ破綻するかの背景。
RDB / DDL — 約束(制約)をスキーマとして宣言する仕組み。
メタデータ — 「どの列がキーか」を文書化するデータ辞書の考え方。