PythonのSQL文の基本構文(SELECT・INSERT・UPDATE・DELETE)
生徒
「先生、データベースを操作するためのSQL文って、どんな種類があるんですか?」
先生
「データベース操作には、主に4つの基本的なSQL文があります。データを取得するSELECT、データを追加するINSERT、データを更新するUPDATE、そしてデータを削除するDELETEです。」
生徒
「4つだけなら覚えられそうですね!それぞれどんな時に使うんですか?」
先生
「それでは、これらの基本構文を一つずつ詳しく見ていきましょう!」
1. SQL文とは?データベース操作の基本言語
SQL(エスキューエル)は、Structured Query Language(構造化問い合わせ言語)の略で、データベースを操作するための専用の言語です。SQLを使うことで、データベースに保存されているデータを自由に扱えるようになります。
SQLは、普通のプログラミング言語とは少し違います。データベースに対して「こういうデータが欲しい」「このデータを保存して」といった命令を出すための言語です。例えるなら、図書館の司書さんに本を探してもらうときの依頼書のようなものです。
SQL文の4つの基本操作(CRUD)
データベース操作の基本は、CRUD(クラッド)と呼ばれる4つの操作です:
- Create(作成):新しいデータを追加する →
INSERT文 - Read(読み取り):データを取得する →
SELECT文 - Update(更新):既存のデータを変更する →
UPDATE文 - Delete(削除):データを削除する →
DELETE文
2. SELECT文:データを取得する
SELECT文は、データベースからデータを取り出すためのSQL文です。最もよく使われる命令で、「このデータを見せて」と依頼するイメージです。
SELECT文の基本構文
基本的な構文は以下の通りです:
SELECT 列名 FROM テーブル名 WHERE 条件;
実際にPythonでSQLiteを使って、SELECT文を実行してみましょう:
import sqlite3
# データベースに接続
connection = sqlite3.connect('school.db')
cursor = connection.cursor()
# すべての列を取得
cursor.execute("SELECT * FROM students")
all_students = cursor.fetchall()
print("=== 全生徒のデータ ===")
for student in all_students:
print(student)
# 特定の列だけを取得
cursor.execute("SELECT name, age FROM students")
names_ages = cursor.fetchall()
print("\n=== 名前と年齢だけを取得 ===")
for data in names_ages:
print(f"名前: {data[0]}, 年齢: {data[1]}")
connection.close()
WHERE句で条件を指定する
WHERE句を使うと、特定の条件に合うデータだけを取得できます。これは、大量のデータの中から必要なものだけを絞り込むフィルターのような機能です。
import sqlite3
connection = sqlite3.connect('school.db')
cursor = connection.cursor()
# 条件を指定してデータを取得
cursor.execute("SELECT * FROM students WHERE age >= ?", (18,))
adult_students = cursor.fetchall()
print("=== 18歳以上の生徒 ===")
for student in adult_students:
print(f"名前: {student[1]}, 年齢: {student[2]}")
# 複数の条件を組み合わせる
cursor.execute("SELECT name, score FROM students WHERE score >= ? AND age < ?", (80, 20))
high_scorers = cursor.fetchall()
print("\n=== 80点以上で20歳未満の生徒 ===")
for student in high_scorers:
print(f"名前: {student[0]}, 点数: {student[1]}")
connection.close()
よく使われる条件演算子:
=:等しい!=または<>:等しくない>:より大きい<:より小さい>=:以上<=:以下AND:かつ(両方の条件を満たす)OR:または(どちらかの条件を満たす)
3. INSERT文:新しいデータを追加する
INSERT文は、テーブルに新しいデータを追加するためのSQL文です。ノートに新しい情報を書き込むようなイメージです。
INSERT文の基本構文
INSERT INTO テーブル名 (列名1, 列名2, ...) VALUES (値1, 値2, ...);
import sqlite3
connection = sqlite3.connect('school.db')
cursor = connection.cursor()
# 1件のデータを追加
cursor.execute(
"INSERT INTO students (name, age, score) VALUES (?, ?, ?)",
('田中太郎', 17, 85)
)
print("1件のデータを追加しました")
# 複数のデータを一度に追加
students_data = [
('佐藤花子', 18, 92),
('鈴木一郎', 16, 78),
('高橋美咲', 19, 88)
]
cursor.executemany(
"INSERT INTO students (name, age, score) VALUES (?, ?, ?)",
students_data
)
print(f"{cursor.rowcount}件のデータを追加しました")
# 変更を保存
connection.commit()
# 追加されたデータを確認
cursor.execute("SELECT * FROM students")
all_data = cursor.fetchall()
print(f"\n現在の総データ数: {len(all_data)}件")
connection.close()
INSERT文を実行した後は、必ずcommit()メソッドを呼び出してください。これを忘れると、データが保存されません。
プレースホルダーの使用
上記のコードで使っている?は、プレースホルダーと呼ばれます。これを使うことで、SQLインジェクション攻撃という危険な攻撃を防ぐことができます。値を直接SQL文に埋め込まず、必ずプレースホルダーを使用してください。
4. UPDATE文:既存のデータを更新する
UPDATE文は、すでにテーブルに存在するデータを変更するためのSQL文です。ノートに書いた内容を修正するようなイメージです。
UPDATE文の基本構文
UPDATE テーブル名 SET 列名1 = 値1, 列名2 = 値2 WHERE 条件;
import sqlite3
connection = sqlite3.connect('school.db')
cursor = connection.cursor()
# 特定の生徒の点数を更新
cursor.execute(
"UPDATE students SET score = ? WHERE name = ?",
(95, '田中太郎')
)
print(f"{cursor.rowcount}件のデータを更新しました")
# 複数の列を同時に更新
cursor.execute(
"UPDATE students SET age = ?, score = ? WHERE name = ?",
(18, 90, '佐藤花子')
)
print(f"{cursor.rowcount}件のデータを更新しました")
# 条件に合うすべてのデータを更新
cursor.execute(
"UPDATE students SET score = score + ? WHERE score < ?",
(5, 80)
)
print(f"{cursor.rowcount}件のデータに5点加算しました")
# 変更を保存
connection.commit()
# 更新後のデータを確認
cursor.execute("SELECT name, age, score FROM students")
updated_data = cursor.fetchall()
print("\n=== 更新後のデータ ===")
for student in updated_data:
print(f"名前: {student[0]}, 年齢: {student[1]}, 点数: {student[2]}")
connection.close()
UPDATE文でWHERE句を指定しないと、テーブル内のすべてのデータが更新されてしまいます。必ず更新対象を明確に指定してください。
5. DELETE文:データを削除する
DELETE文は、テーブルからデータを削除するためのSQL文です。一度削除したデータは元に戻せないため、慎重に使用する必要があります。
DELETE文の基本構文
DELETE FROM テーブル名 WHERE 条件;
import sqlite3
connection = sqlite3.connect('school.db')
cursor = connection.cursor()
# 特定の生徒を削除
cursor.execute(
"DELETE FROM students WHERE name = ?",
('鈴木一郎',)
)
print(f"{cursor.rowcount}件のデータを削除しました")
# 条件に合うデータを削除
cursor.execute(
"DELETE FROM students WHERE score < ?",
(60,)
)
print(f"{cursor.rowcount}件のデータを削除しました(60点未満)")
# 変更を保存
connection.commit()
# 削除後のデータ数を確認
cursor.execute("SELECT COUNT(*) FROM students")
count = cursor.fetchone()[0]
print(f"\n現在の生徒数: {count}名")
# 残っているデータを表示
cursor.execute("SELECT * FROM students")
remaining_data = cursor.fetchall()
print("\n=== 残っているデータ ===")
for student in remaining_data:
print(f"ID: {student[0]}, 名前: {student[1]}, 年齢: {student[2]}, 点数: {student[3]}")
connection.close()
DELETE文でWHERE句を指定しないと、テーブル内のすべてのデータが削除されてしまいます。これは取り返しのつかない操作なので、特に注意が必要です。
6. ORDER BY句:データを並び替える
ORDER BY句を使うと、取得したデータを特定の順序で並び替えることができます。データを見やすく整理するために非常に便利な機能です。
昇順と降順の指定
ASC:昇順(小さい順、古い順)※省略可能DESC:降順(大きい順、新しい順)
import sqlite3
connection = sqlite3.connect('school.db')
cursor = connection.cursor()
# 点数の高い順に並び替え
cursor.execute("SELECT name, score FROM students ORDER BY score DESC")
sorted_data = cursor.fetchall()
print("=== 点数の高い順 ===")
for i, student in enumerate(sorted_data, 1):
print(f"{i}位: {student[0]} ({student[1]}点)")
# 年齢の若い順に並び替え
cursor.execute("SELECT name, age FROM students ORDER BY age ASC")
age_sorted = cursor.fetchall()
print("\n=== 年齢の若い順 ===")
for student in age_sorted:
print(f"{student[0]}: {student[1]}歳")
# 複数の列で並び替え(年齢→点数の順)
cursor.execute("SELECT name, age, score FROM students ORDER BY age DESC, score DESC")
multi_sorted = cursor.fetchall()
print("\n=== 年齢順、同年齢なら点数順 ===")
for student in multi_sorted:
print(f"{student[0]}: {student[1]}歳, {student[2]}点")
connection.close()
7. LIMIT句:取得件数を制限する
LIMIT句を使うと、取得するデータの件数を制限できます。大量のデータがある場合に、必要な分だけを取得するのに便利です。
import sqlite3
connection = sqlite3.connect('school.db')
cursor = connection.cursor()
# 上位3名だけを取得
cursor.execute("SELECT name, score FROM students ORDER BY score DESC LIMIT 3")
top_three = cursor.fetchall()
print("=== 成績上位3名 ===")
for i, student in enumerate(top_three, 1):
print(f"{i}位: {student[0]} ({student[1]}点)")
# 4位から6位を取得(OFFSETを使用)
cursor.execute("SELECT name, score FROM students ORDER BY score DESC LIMIT 3 OFFSET 3")
next_three = cursor.fetchall()
print("\n=== 4位~6位 ===")
for i, student in enumerate(next_three, 4):
print(f"{i}位: {student[0]} ({student[1]}点)")
connection.close()
OFFSETを使うと、指定した件数だけスキップしてからデータを取得できます。ページネーション(ページ分割)を実装する際に役立ちます。
8. 集計関数:データを集計する
SQL文には、データを集計するための便利な関数が用意されています。これらを使うことで、合計や平均などを簡単に計算できます。
主な集計関数
COUNT():データの件数を数えるSUM():合計を計算するAVG():平均を計算するMAX():最大値を取得するMIN():最小値を取得する
import sqlite3
connection = sqlite3.connect('school.db')
cursor = connection.cursor()
# 生徒の総数を取得
cursor.execute("SELECT COUNT(*) FROM students")
total_count = cursor.fetchone()[0]
print(f"総生徒数: {total_count}名")
# 平均点を計算
cursor.execute("SELECT AVG(score) FROM students")
average_score = cursor.fetchone()[0]
print(f"平均点: {average_score:.1f}点")
# 最高点と最低点を取得
cursor.execute("SELECT MAX(score), MIN(score) FROM students")
max_score, min_score = cursor.fetchone()
print(f"最高点: {max_score}点, 最低点: {min_score}点")
# 合計点を計算
cursor.execute("SELECT SUM(score) FROM students")
total_score = cursor.fetchone()[0]
print(f"全員の合計点: {total_score}点")
# 年齢ごとの人数を集計(GROUP BY)
cursor.execute("SELECT age, COUNT(*) FROM students GROUP BY age")
age_groups = cursor.fetchall()
print("\n=== 年齢別の生徒数 ===")
for age, count in age_groups:
print(f"{age}歳: {count}名")
connection.close()
9. SQL文を組み合わせた実践例
これまで学んだSQL文を組み合わせて、実際のアプリケーションに近い処理を実装してみましょう。
import sqlite3
def show_student_stats():
"""生徒の統計情報を表示する関数"""
connection = sqlite3.connect('school.db')
cursor = connection.cursor()
# 総数と平均点を取得
cursor.execute("SELECT COUNT(*), AVG(score) FROM students")
count, avg_score = cursor.fetchone()
print(f"=== 統計情報 ===")
print(f"生徒数: {count}名")
print(f"平均点: {avg_score:.1f}点")
# 成績上位3名を表示
cursor.execute("SELECT name, score FROM students ORDER BY score DESC LIMIT 3")
top_students = cursor.fetchall()
print("\n=== 成績上位3名 ===")
for i, (name, score) in enumerate(top_students, 1):
print(f"{i}位: {name} ({score}点)")
# 平均点以上の生徒数を集計
cursor.execute("SELECT COUNT(*) FROM students WHERE score >= ?", (avg_score,))
above_avg_count = cursor.fetchone()[0]
print(f"\n平均点以上の生徒: {above_avg_count}名")
connection.close()
# 関数を実行
show_student_stats()
この例では、複数のSQL文を組み合わせて、生徒の統計情報を表示する実用的な機能を実装しています。実際のアプリケーション開発でも、このように複数のSQL文を組み合わせて使うことが多いです。
10. SQL文を書く際の重要なポイント
SQL文を安全かつ効率的に使うために、押さえておくべき重要なポイントをまとめました。
セキュリティのポイント
- 必ずプレースホルダー(
?)を使用する - ユーザー入力を直接SQL文に埋め込まない
- 文字列の連結でSQL文を作成しない
データ保護のポイント
UPDATEやDELETEでは必ずWHERE句を指定する- 重要な操作の前にSELECTで対象データを確認する
commit()を実行する前に処理内容を再確認する- 本番環境では削除前にバックアップを取る
パフォーマンスのポイント
- 必要な列だけを取得する(
SELECT *を避ける) - インデックスを適切に設定する
- 大量のデータを扱う場合は
LIMIT句を使う - 複数のデータを追加する場合は
executemany()を使う
開発のヒント
SQL文を書く際は、まず小さなテストデータで動作確認してから本番データに適用することをおすすめします。また、複雑なSQL文を書く場合は、段階的に構築していくと間違いが少なくなります。
エラーが発生した場合は、エラーメッセージをよく読んで、どこが間違っているのか確認しましょう。SQLiteやMySQLなどのデータベースツールを使えば、SQL文を直接実行してテストできるので便利です。