0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【初心者向け】Python × SQLite で法人データベースを作ろう

0
Last updated at Posted at 2026-07-03

はじめに

特別なセットアップなしで手軽に始められる「SQLite」を使い、Python によるデータベース構築を学びます。

教材用のサンプルデータではなく、より実践的なデータを扱うため、今回は国税庁が提供する実際の「法人全件データ (CSV)」を活用します。

コードもカラム構成も最小限に抑えたシンプルな設計にしているため、データベースの基礎を学ぶのに適しているかと思います。

チュートリアルを終えた後は、必要に応じて自由にカスタマイズしてください。

目次

対象レベル (目安)

  • VSCodeなどテキストエディタが使える
  • SQLの基本概念や基本構文を知っている
    • CREATE, INSERT, SELECT, DELETE, など
  • Pythonの基本文法が分かる
    • for, if, def, with, import, など
    • ※ 上記以外にも pathlib や型ヒントを使った書き方が登場しますが、意味が分からなくても後続の理解には影響しません。気になる方はその都度調べながら読み進めてください。

SQLiteの扱いについては、以下のリンクにあるチュートリアルコードを軽く試しておくと、理解がしやすいかもしれません。

参考リンク

必要環境

  • Python 3.10 以上(str | None 形式の型ヒントを使用しています)
  • 標準ライブラリのみで動作します(例: sqlite3, csv, pathlib)。追加のパッケージインストールは不要です。
補足説明
  • 任意ですが、処理の進捗を表示したい場合は tqdm をインストールします。詳細は後述します。

1. 準備編

データベースを作成する前に、法人データを用意するなど、下準備をしていきます。

1-1. 初期ディレクトリ構成

以下の構成にし、テキストエディタで root フォルダを開いておきましょう。

root/
 ├─ data/      # 法人データを配置します。
 └─ config.py  # データベース接続情報やファイルパスなどを記述します(後述)。
補足説明
  • root は任意の名称で問題ありません。(例: corporate_db)
  • 最終的には config.py 以外にもファイルを作成していきますが、順番に示していきます。

1-2. 法人全件データの用意

以下のリンクにアクセスし、CSV形式・Unicodeかつ「全国」のzipファイルをダウンロードします。(ファイル名の例: 00_zenkoku_all_20260630.zip)

ダウンロード先のリンク

ダウンロードしたzipファイルを解凍すると、00_zenkoku_all_20260630.csvのような名前のCSVファイルがあることを確認できます。

このCSVファイルを、root/data/に配置しておきましょう。

root/
 ├─ data/
 │   └─ 00_zenkoku_all_20260630.csv
 └─ config.py
CSVファイルの構造 (参考)

ファイルサイズが 1GB を超えるため、VSCode で開く際に困難な場合があります。開けない場合の参考として、CSVファイルの冒頭数行を記述しておきます。

1,1000012160153,01,1,2018-04-02,2015-10-05,"釧路検察審査会",,101,"北海道","釧路市","柏木町4-7",,01,206,0850824,,,,,,,2015-10-05,1,"Kushiro Committee for the Inquest of Prosecution","Hokkaido","4-7, Kashiwagicho, Kushiro shi",,"クシロケンサツシンサカイ",0
2,1000013050386,01,1,2018-04-02,2015-10-05,"伊達簡易裁判所",,101,"北海道","伊達市","末永町47-10",,01,233,0520021,,,,,,,2015-10-05,1,"Date Summary Court","Hokkaido","47-10, Suenagacho, Date shi",,"ダテカンイサイバンショ",0
3,1000013050394,01,1,2018-04-02,2015-10-05,"八雲簡易裁判所",,101,"北海道","二海郡八雲町","末広町184",,01,346,0493112,,,,,,,2015-10-05,1,"Yakumo Summary Court","Hokkaido","184, Suehirocho, Yakumo cho, Futami gun",,"ヤクモカンイサイバンショ",0

※ 2026年6月30日時点の情報です。

各列の意味は、国税庁が提供している「リソース定義書」を確認してください。

参考リンク

1-3. 除外ファイルの設定 (参考)

Gitでソースコードを管理している場合は、データベース本体や大容量のCSVファイルはGitHubなどにアップロードしないよう、除外設定をしておきましょう。

.gitignore はGitのバージョン管理から除外するファイルやディレクトリを指定する設定ファイルです。

root/.gitignore を新規作成し、以下のように記述します。(それぞれの必要に応じて追加してください)

.gitignore
# 法人データ
*.csv

# データベースファイル
*.db

# キャッシュファイル
__pycache__/

# 仮想環境
.venv

2. データベース構築編

CSVファイルの配置が完了したら、いよいよデータベースを作成していきます。

2-1. データベース構造の確認

コードを書いていく前に、今回扱うデータベースの構造を確認しておきましょう。

今回は最小限のカラム構成にしています。ご自身の学習状況や必要に応じて、上記の「リソース定義書」やCSVを確認しながらカラムを追加してみてください。

【テーブル情報】

論理テーブル名 物理テーブル名
法人テーブル corporate_registry

【カラム情報】

論理名 物理名 データ型 PK Null
法人番号 corporate_number TEXT ◯ ×
法人名 corporate_name TEXT ×

【インデックス情報】

インデックス名 種別 構成カラム ユニーク 備考 / 特記事項
sqlite_autoindex_corporate_registry_1 B-Tree corporate_number ◯ 主キー(PK)の作成に伴い、SQLiteにより自動生成されるインデックス
index_corporate_name B-Tree corporate_name × 法人名による前方一致・完全一致検索の高速化
補足説明

主キーについて

  • 法人番号とは、国税庁が株式会社などの法人や国の機関、地方公共団体に指定している13桁の識別番号です。重複がなく、不変性が非常に高いといえます。
  • 今回は日本国内の登記法人情報を格納するだけであるため、IDのような連番を主キー (サロゲートキー) にするのではなく、法人番号を主キー (ナチュラルキー) としています。

インデックスについて

  • B-Treeインデックスは先頭から順番に文字を比較していくため、中間一致や後方一致による検索といったケースでは機能しません。

2-2. データベース接続情報およびファイルパスの指定

はじめに、複数の Python ファイル (以下: モジュール) から呼び出す共有の定数を定義していきます。

root/config.py に以下の内容を記述します。

config.py
"""データベース接続情報やファイルパスを管理するモジュール"""

from pathlib import Path

# 実行中のスクリプトのパスを取得
SCRIPT_PATH = Path(__file__).resolve()
# スクリプトが配置されているディレクトリのパスを取得
BASE_DIR = SCRIPT_PATH.parent

# 法人データCSVのファイル名・配置場所 (実際のファイル名に合わせて書き換えてください)
CSV_NAME = "00_zenkoku_all_20260630.csv"
CSV_PATH = BASE_DIR / "data" / CSV_NAME

# データベースのファイル名・配置場所
DB_NAME = "corporate.db"
DB_PATH = BASE_DIR / DB_NAME

2-3. データベース&テーブル作成

次に、テーブル作成を実行するモジュールを作成しましょう。

root/create_table.py を新規作成し、以下の内容を記述します。

create_table.py
"""法人テーブルを作成するモジュール"""

from config import DB_PATH

import sqlite3

# DBに接続
connection = sqlite3.connect(database=DB_PATH)
cursor = connection.cursor()

# SQL文の定義
create_table_sql = """
-- 1. テーブル作成
CREATE TABLE
    IF NOT EXISTS corporate_registry (
        corporate_number TEXT PRIMARY KEY, -- 法人番号
        corporate_name TEXT NOT NULL       -- 法人名
    );

-- 2. 法人名にインデックスを付与(完全一致・前方一致検索などの高速化)
CREATE INDEX IF NOT EXISTS index_corporate_name ON corporate_registry (corporate_name);
"""

# テーブル作成処理実行 (複数の命令を同時に実行)
cursor.executescript(create_table_sql)
# コミットして保存を確定する
connection.commit()

# 参考: テーブル名確認
response = cursor.execute("SELECT name FROM sqlite_master")
data = response.fetchone()[0]
print("テーブル名:", data)

ファイルへの記述が完了したら、以下のコマンドで実行しましょう。

python create_table.py

正常に処理が完了したら、root/corporate.dbというファイルが生成されているはずです。

補足説明

IF NOT EXISTS について:

  • 「存在しない場合」にのみ実行する構文です。(EXISTS: 存在するという意味)
  • 何度実行してもエラーにならないようにしています。

インデックス作成の構文について:

  • CREATE INDEX インデックス名 ON テーブル名 (カラム名);

2-4. データベースの確認 (参考)

データベースを確認するために、今回は簡単な例として VSCode の拡張機能 SQLite (alexcvzz氏作成) を利用した場合の開き方を示します。

  1. データベースファイルがあるフォルダをVSCodeで開きます。
  2. コマンドパレットを開きます(Windows/Linuxは Ctrl+Shift+P、Macは Cmd+Shift+P)。
  3. SQLite: Open Database と入力し、候補から対象のデータベースファイルを選択します。
  4. サイドバーのエクスプローラー下部に「SQLITE EXPLORER」という項目が新しく表示され、そこから確認することができます。

3. データ投入編

ここからは、CSVからデータベースに値を挿入する処理を作成していきます。

3-1. 処理の全体像

まずはじめに、データ投入に必要な全体のフローを簡単に整理しておきましょう。

  1. DBに接続する
  2. 既存のデータをクリアする(※)
  3. CSV開き、各行を読み込む
  4. 行から値を取得する
  5. 法人番号と法人名が存在していたらDBに挿入する
  6. 変更を確定する

※ 今回は何度実行しても同じ結果となるよう、投入処理実行時に既存のデータを一旦クリアし、CSVのデータで全件洗い替える形式をとります。

3-2. 補助関数の作成

まずはじめに、CSVから値を取り出すための補助関数を作成します。

root/csv_util.py を新規作成し、以下の内容を記述します。

csv_util.py
"""CSVから値を抽出するためのヘルパーモジュール"""

def get_csv_value(index: int, row: list[str]) -> str | None:
    """CSVのカラムインデックスから文字列を抽出し、トリミングします。

    指定されたインデックスの値を取得し、前後の空白を削除します。
    トリミング後の値が空文字("")の場合は、Noneを返します。

    Args:
        index (int): 抽出する要素の列インデックス。
        row (list[str]): CSVの1行分のデータが含まれる文字列のリスト。

    Returns:
        str | None: トリミングされた文字列。空文字の場合は None。
    """
    value = row[index].strip()
    return value or None

# 動作確認用
if __name__ == "__main__":
    import csv
    from config import CSV_PATH

    LIMIT_ROWS = 10  # 読み込む最大行数

    print("=== 法人CSVを開いて内容を確認します ===")
    print(f"対象ファイルパス: {CSV_PATH}\n")

    # CSVファイルを直接開いて読み込む
    with open(CSV_PATH, "r", encoding="utf-8") as csv_file:
        reader = csv.reader(csv_file)

        for count, row in enumerate(iterable=reader, start=1):
            if count > LIMIT_ROWS:
                break
            # 該当行の特定のカラムインデックスから値を取得
            corporate_number = get_csv_value(index=1, row=row)
            corporate_name = get_csv_value(index=6, row=row)
            print(f"------ {count}行目 ------")
            print(f"{row}\n")
            print(f"法人番号: {corporate_number}")
            print(f"法人名  : {corporate_name}\n")
補足説明
  • if __name__ == "__main__": 以降は必須ではありませんが、python csv_util.py から個別で動作確認したい場合に便利です。実際の投入処理でもこのロジックを利用します。
  • 今回扱う法人データのCSVにはヘッダー行が存在しません。もし1行目にヘッダー(カラム名等)が入っているCSVを扱う場合は、next(reader) などを使って1行目をスキップする必要があります。

3-3. データ投入処理の作成

次に、本体となるモジュールを作成していきます。

root/insert_data.py を新規作成し、以下の内容を記述します。

insert_data.py
"""国税庁の法人全件データ(CSV形式)をSQLite3にインポートするモジュール"""

import csv
import sqlite3

# 設定情報
from config import CSV_PATH, DB_PATH

# CSVから値を取り出すための補助関数
from csv_util import get_csv_value


def import_corporate_data_from_csv() -> None:
    """法人データのCSVファイルを読み込み、全件洗い替えで保存するメイン処理"""

    print("=== 法人データのインポートを開始します ===")
    print(f"対象ファイル: {CSV_PATH}")

    # DBに接続
    with sqlite3.connect(database=DB_PATH) as connection:
        cursor = connection.cursor()

        # 1. 既存のデータをクリア(全件洗い替えのため)
        print("\n既存の法人データをクリアしています (DELETE FROM)...")
        cursor.execute("DELETE FROM corporate_registry;")

        # 2. CSVファイルを開いて読み込む
        print("CSVから法人データを投入しています (INSERT INTO)...")
        print("(処理には数十秒〜数分かかります)")
        with open(file=CSV_PATH, mode="r", encoding="utf-8") as csv_file:
            reader = csv.reader(csv_file)

            # 3. INSERT用のSQL文を準備 (名前付きプレースホルダー `:変数名` を使用)
            insert_query = """
                INSERT INTO corporate_registry (
                    corporate_number,
                    corporate_name
                ) VALUES (
                    :corporate_number_data,
                    :corporate_name_data
                )
            """

            # 4. CSVの行を1件ずつ取り出して処理するループ
            for row in reader:
                # 行から挿入する値を取得
                corporate_number = get_csv_value(index=1, row=row)
                corporate_name = get_csv_value(index=6, row=row)

                # どちらかが None なら、この行の処理はスキップして次の行へ
                if corporate_number is None or corporate_name is None:
                    continue

                # INSERT文に渡すためのデータセット(辞書)を作成
                insert_values_dict = {
                    "corporate_number_data": corporate_number,
                    "corporate_name_data": corporate_name,
                }

                # 1件ずつDBにINSERTを実行
                cursor.execute(insert_query, insert_values_dict)

        # 5. ループがすべて終わった最後に、1回だけコミットして保存を確定する
        connection.commit()

    print("\n=== 処理が完了しました ===")


# 実行
if __name__ == "__main__":
    import_corporate_data_from_csv()

ファイルへの記述が完了したら、以下のコマンドで実行しましょう。

python insert_data.py

正常に処理が完了したら、corporate.db に法人番号と法人名が格納されているのを確認しましょう。

補足説明

処理時間と進捗表示について

  • 処理には数十秒から数分程度かかります。
  • tqdm を用いれば処理の進捗状況を表示できます。仮想環境に pip install tqdm でライブラリを追加したのちに、for文の箇所を以下のように差し替えます。
insert_data.py
# 冒頭に追加
from tqdm import tqdm

# ...(中略)
# for row in reader:
for row in tqdm(iterable=reader, desc="インポート進捗", unit="件"):

コミットについて

  • もし1件INSERTするごとに毎回コミット(保存)を行うと、ディスクへの書き込みが頻発し、処理時間が増大してしまいます。
  • 今回はループ処理の最後にまとめてコミットすることで高速化しています。

最適化について

  • 処理の流れを理解しやすくするため、今回は1件ずつ execute で挿入する最も基本的な手法を採用しており、最適化は最小限に留めています。
  • 基礎を身につけた後の次のステップとして、興味がある方はぜひ「SQLite executemany」などで調べてみてください。

最終的なディレクトリ構成

一連のコードを書いた後は、以下のようなディレクトリ構成になっています。

root/
 ├─ data/
 │   └─ 00_zenkoku_all_20260630.csv # 法人データ
 ├─ config.py        # データベース接続情報やファイルパスなど
 ├─ create_table.py  # テーブル作成
 ├─ csv_util.py      # 補助関数
 ├─ insert_data.py   # データ投入
 ├─ corporate.db     # データベースファイル
 └─ .gitignore       # バージョン管理から除外するファイル等の指定

おわりに

本記事では、国税庁が提供する実データを利用して、PythonとSQLiteによるシンプルな法人データベースを構築しました。まずは「動くものを作る」という最初のハードルを越えられたかと思います。

ここからさらにデータベースに対する理解を深めるうえで有効な、次のステップへのヒントをいくつか紹介します。

  • カラムの追加
    今回は「法人番号」と「法人名」の2つに絞りましたが、CSVには所在地、法人種別、設立年月日などの豊富なデータが含まれています。「リソース定義書」を参考に CREATE TABLE 文やデータ投入処理を書き換えて、各々の要件に合わせたカラムを追加してみてください。

  • SELECT文によるデータの取得と活用
    データを格納した後は、取り出して活用するのがデータベースの醍醐味です。Pythonコードから SELECT 文を実行し、「特定の都道府県の法人を抽出する」「法人名で検索機能を作る」といったデータ取得の処理を実装してみましょう。

  • パフォーマンスの最適化
    今回作成したスクリプトでも動作しますが、数百万件のデータをさらに高速に処理するための手法が存在します。補足で触れた executemany を使った一括挿入などを実際に試してみると、パフォーマンスチューニングの基礎を体感できます。

今回のコードはチュートリアル用のシンプルな設計にしているため、拡張の余地はたくさんあります。ぜひご自身の興味に合わせて、自由にカスタマイズを楽しんでください。

この記事を書いた背景

今回のコードは、私が普段から開発を進めているアプリで実際に使用している法人テーブルの構築処理を、初心者向けに落とし込んだものです。

普段は PostgreSQL を利用していますが、初心者でもより手軽に本格的なデータを扱えるようにするため、Python 標準ライブラリである sqlite3 で動くように書き換えました。

実際に使用している投入処理では、バルクインサートをはじめとする最適化を施していますが、初心者向けということで最適化は意図的に最小限にしつつ、複雑な記述を可能な限り減らしました。

最小限の最適化とはいえ、今回作成したコードを試しに実行してみると、想定以上に処理が早く終わり、私の環境では十数秒で完了していました。(※処理速度はマシンスペックなど環境に大きく左右されるかと思います)

今回の sqlite3 版の処理を書いてみて、SQLite に対する理解が深まっただけでなく、実際に使用しているコードも更にシンプルに書けそうだなという気づきが得られました。

「初心者でも理解しやすいか」という視点を持ってリファクタリングをしてみるのも有効かもしれませんね。

GitHubリポジトリ

今回扱った一連のコードについては、GitHubで公開しています。
手早く内容を確認したい人や、エラーで困った人は、こちらを参考にしてください。

リポジトリへのリンク

参考リンク集

SQLite関連

法人データ関連

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?