基礎から学ぶPython入門 90日コース | データベース・Web API - Day 63:データ操作

Python 90日で身につけるPython
スポンサーリンク
スポンサーリンク

Day 63:データ操作 ― 「増やす・直す・消す」でテーブルを生きたものにする

Day 63では、データベースの世界でとても重要な3つの動きを扱います。

  • INSERT:新しいレコードを「追加」する
  • UPDATE:既存のレコードを「更新」する
  • DELETE:いらなくなったレコードを「削除」する

昨日までの SELECT は「読む」操作でしたが、 今日は「書く・直す・消す」という、より“生活感”のある操作に踏み込んでいきます。

テーブルがただの「静止した表」ではなく、 時間とともに変化していく生きたデータ に見えてくるはずです。

データ操作の全体像をイメージする

3つの基本動作で、ほとんどのCRUDができてしまう

データベースの世界では、よく CRUD という言葉が出てきます。

  • Create → INSERT(作る)
  • Read → SELECT(読む)
  • Update → UPDATE(直す)
  • Delete → DELETE(消す)

今日はこのうち、C / U / D をしっかり体験していきます。

例として、Day 61・62で使った users テーブルをそのまま使います。

CREATE TABLE IF NOT EXISTS users (
    id   INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT NOT NULL,
    age  INTEGER
);

このテーブルに対して、 「ユーザーを追加する」「メールアドレスを直す」「ユーザーを削除する」 といった操作を、Python+SQLiteで書いていきます。

INSERT ― 新しいレコードを追加する

INSERTの基本形を押さえる

まずは、INSERT からいきましょう。

新しいユーザーを登録したい

という場面をイメージします。

SQLの基本形はこうです。

INSERT INTO users (name, email, age)
VALUES ('Taro', 'taro@example.com', 25);

Python+SQLiteで書くと、こんな感じになります。

# day63_data_ops.py
import sqlite3
from pathlib import Path


def get_connection(db_name: str = "day61_example.db") -> sqlite3.Connection:
    """
    SQLiteデータベースに接続するための関数です。
    すでに作成済みの DB を再利用します。
    """
    return sqlite3.connect(Path(db_name))


def insert_user(conn: sqlite3.Connection, name: str, email: str, age: int | None = None) -> None:
    """
    users テーブルに新しいユーザーを追加する関数です。
    1回の呼び出しで、1レコード(1行)が追加されます。
    """

    print(f"[INSERT] ユーザーを追加します: name={name}, email={email}, age={age}")

    sql = """
    INSERT INTO users (name, email, age)
    VALUES (?, ?, ?);
    """

    cur = conn.cursor()
    # ? プレースホルダに、Python側の値を渡します。
    cur.execute(sql, (name, email, age))
    conn.commit()

    print("[INSERT] ユーザーの追加が完了しました。")
Python

プレースホルダを使う理由をしっかり理解しておく

ここは少し深掘りしておきたいポイントです。

  • VALUES (?, ?, ?)? は「あとで値を差し込む場所」です。
  • cur.execute(sql, (name, email, age)) で、Python側の値を安全に埋め込みます。
  • 文字列連結で "... VALUES ('" + name + "', ..." のように書くと、 入力値に悪意のある文字列が混ざったときに、SQLインジェクションの危険が出てきます。

「SQLは必ずプレースホルダ+executeで書く」 この癖を早めにつけておくと、後々の安全性がぐっと高まります。

UPDATE ― 既存のレコードを更新する

UPDATEの基本形

次に、UPDATE です。

あるユーザーのメールアドレスを変更したい

という場面を考えてみます。

SQLの基本形はこうです。

UPDATE users
SET email = 'new@example.com'
WHERE id = 1;
  • SET で「どのカラムをどう変えるか」を指定
  • WHERE で「どのレコードを対象にするか」を指定

Pythonで書くと、こうなります。

def update_user_email(conn: sqlite3.Connection, user_id: int, new_email: str) -> None:
    """
    指定した id のユーザーのメールアドレスを更新する関数です。
    """

    print(f"[UPDATE] ユーザーのメールアドレスを更新します: id={user_id}, new_email={new_email}")

    sql = """
    UPDATE users
    SET email = ?
    WHERE id = ?;
    """

    cur = conn.cursor()
    # SET の ? に new_email、WHERE の ? に user_id を渡します。
    cur.execute(sql, (new_email, user_id))
    conn.commit()

    print("[UPDATE] メールアドレスの更新が完了しました。")
Python

WHEREなしのUPDATEは「全件更新」になる

ここで、かなり重要な注意点があります。

もし、こんなふうに書いてしまったらどうなるでしょうか。

UPDATE users
SET email = 'test@example.com';

WHERE がありません。

この場合、users テーブルの全レコードの email が同じ値に書き換えられてしまいます。

怖いですよね。

UPDATEを書くときは、

  • 「どのカラムを変えるか」
  • 「どのレコードを対象にするか」

この2つをセットで意識することが、とても大事です。

DELETE ― レコードを削除する

DELETEの基本形

最後に、DELETE です。

あるユーザーを削除したい

という場面を考えます。

SQLの基本形はこうです。

DELETE FROM users
WHERE id = 1;

Pythonで書くと、こうなります。

def delete_user(conn: sqlite3.Connection, user_id: int) -> None:
    """
    指定した id のユーザーを削除する関数です。
    """

    print(f"[DELETE] ユーザーを削除します: id={user_id}")

    sql = """
    DELETE FROM users
    WHERE id = ?;
    """

    cur = conn.cursor()
    cur.execute(sql, (user_id,))
    conn.commit()

    print("[DELETE] ユーザーの削除が完了しました。")
Python

DELETEも「WHEREなし」はとても危険

UPDATEと同じく、DELETEも WHERE がないと危険です。

DELETE FROM users;

これは、users テーブルの全レコードを削除する という意味になります。

もちろん、意図的に「全件削除」したい場面もありますが、 多くの場合は「うっかり」だと大惨事です。

DELETEを書くときは、 「本当にこの条件で合っているか?」 を一度立ち止まって確認する癖をつけておくと安心です。

INSERT・UPDATE・DELETEをまとめて試すミニプロジェクト

ここまでの3つを、ひとつの流れで試せるように、 Day 63ミニプロジェクト としてまとめてみます。

# day63_crud_demo.py
import sqlite3
from pathlib import Path


def get_connection(db_name: str = "day61_example.db") -> sqlite3.Connection:
    return sqlite3.connect(Path(db_name))


def create_users_table(conn: sqlite3.Connection) -> None:
    """
    users テーブルがない場合に作成する関数です。
    Day 61 と同じ定義を使います。
    """
    sql = """
    CREATE TABLE IF NOT EXISTS users (
        id   INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        email TEXT NOT NULL,
        age  INTEGER
    );
    """
    cur = conn.cursor()
    cur.execute(sql)
    conn.commit()


def insert_user(conn: sqlite3.Connection, name: str, email: str, age: int | None = None) -> None:
    sql = "INSERT INTO users (name, email, age) VALUES (?, ?, ?);"
    cur = conn.cursor()
    cur.execute(sql, (name, email, age))
    conn.commit()


def update_user_email(conn: sqlite3.Connection, user_id: int, new_email: str) -> None:
    sql = "UPDATE users SET email = ? WHERE id = ?;"
    cur = conn.cursor()
    cur.execute(sql, (new_email, user_id))
    conn.commit()


def delete_user(conn: sqlite3.Connection, user_id: int) -> None:
    sql = "DELETE FROM users WHERE id = ?;"
    cur = conn.cursor()
    cur.execute(sql, (user_id,))
    conn.commit()


def fetch_all_users(conn: sqlite3.Connection) -> list[tuple]:
    sql = "SELECT id, name, email, age FROM users;"
    cur = conn.cursor()
    cur.execute(sql)
    return cur.fetchall()


def main():
    conn = get_connection()
    create_users_table(conn)

    print("=== INSERT: ユーザーを3人追加します ===")
    insert_user(conn, "Taro", "taro@example.com", 25)
    insert_user(conn, "Hanako", "hanako@example.com", 30)
    insert_user(conn, "Ken", "ken@example.com", 22)

    print("\n=== 現在のユーザー一覧 ===")
    for u in fetch_all_users(conn):
        print(f"id={u[0]}, name={u[1]}, email={u[2]}, age={u[3]}")

    print("\n=== UPDATE: id=1 のメールアドレスを変更します ===")
    update_user_email(conn, user_id=1, new_email="taro.new@example.com")

    print("\n=== UPDATE後のユーザー一覧 ===")
    for u in fetch_all_users(conn):
        print(f"id={u[0]}, name={u[1]}, email={u[2]}, age={u[3]}")

    print("\n=== DELETE: id=2 のユーザーを削除します ===")
    delete_user(conn, user_id=2)

    print("\n=== DELETE後のユーザー一覧 ===")
    for u in fetch_all_users(conn):
        print(f"id={u[0]}, name={u[1]}, email={u[2]}, age={u[3]}")

    conn.close()


if __name__ == "__main__":
    main()
Python

このスクリプトを実行すると、

  1. テーブルがなければ作成
  2. ユーザーを3人追加(INSERT)
  3. 一覧表示
  4. 1人のメールアドレスを更新(UPDATE)
  5. 再度一覧表示
  6. 1人を削除(DELETE)
  7. 最後に一覧表示

という流れが、目で追えるようになっています。

Day 63のまとめ ― データを「動かせる」ようになると、世界が一段階変わる

今日扱ったキーワードは、

  • INSERT:新しいレコードを追加する
  • UPDATE:既存のレコードを更新する
  • DELETE:いらなくなったレコードを削除する

でした。

そして、どの操作でも共通して大事だったのが、

  • プレースホルダ ? を使って、安全に値を渡すこと
  • WHERE で「どのレコードを対象にするか」をきちんと指定すること
  • conn.commit() で変更を確定させること

この3つです。

ここまで来ると、 データベースは「ただ読むだけの箱」ではなく、 「増やして、直して、整理していける、ちゃんとした情報の拠点」 に見えてくるはずです。

タイトルとURLをコピーしました