T-CREATOR

MySQL 基本操作徹底解説:SELECT/INSERT/UPDATE/DELETE の正しい書き方

MySQL 基本操作徹底解説:SELECT/INSERT/UPDATE/DELETE の正しい書き方

データベースの世界に足を踏み入れると、まず最初に出会うのが MySQL です。なぜなら、MySQL は世界中で最も利用されているデータベース管理システムの一つだからです。

でも実は、多くの開発者が MySQL の基本操作で躓いているのが現実です。「なんとなく動いているけど、本当にこの書き方で大丈夫?」そんな不安を抱えながら、日々の開発を進めている方も多いのではないでしょうか。

今回は、MySQL の基本中の基本である 4 つの操作(SELECT・INSERT・UPDATE・DELETE)について、初心者の方でも安心して使える正しい書き方を徹底的に解説いたします。この記事を読み終える頃には、自信を持って SQL 文を書けるようになりますよ。

背景

MySQL データベース操作の重要性

現代の Web アプリケーション開発において、データベース操作は避けて通れません。特に MySQL は、その高いパフォーマンスと安定性から、多くの企業で採用されているデータベース管理システムです。

MySQL の利用シーンを見てみましょう。

mermaidflowchart TD
    web[Webアプリケーション] -->|データ要求| mysql[(MySQL データベース)]
    mobile[モバイルアプリ] -->|データ要求| mysql
    api[REST API] -->|データ要求| mysql
    batch[バッチ処理] -->|データ要求| mysql

    mysql -->|データ応答| web
    mysql -->|データ応答| mobile
    mysql -->|データ応答| api
    mysql -->|データ応答| batch

    subgraph mysql_ops[MySQL基本操作]
        select[SELECT - データ取得]
        insert[INSERT - データ追加]
        update[UPDATE - データ更新]
        delete[DELETE - データ削除]
    end

    mysql -.-> mysql_ops

図から分かるように、様々なアプリケーションが MySQL と連携しており、その基盤となるのが 4 つの基本操作です。

SQL 基本操作の基礎知識

SQL は「Structured Query Language」の略で、データベースとやり取りするための標準的な言語です。MySQL では、この SQL 言語を使ってデータの操作を行います。

SQL 操作は大きく以下のカテゴリに分類されます:

カテゴリ操作名英語表記説明
1データ取得SELECTデータベースからデータを検索・取得する
2データ追加INSERTデータベースに新しいレコードを挿入する
3データ更新UPDATE既存のレコードの内容を変更する
4データ削除DELETE既存のレコードをデータベースから削除する

これらの操作を正しく理解することで、データベースを自在に操ることができるようになります。

実務でよく使用される 4 つの基本コマンド

実際の開発現場では、これら 4 つの操作を組み合わせて様々な機能を実現しています。例えば、EC サイトでは以下のような使い方をします:

  • SELECT: 商品一覧の表示、在庫数の確認
  • INSERT: 新規会員登録、注文データの追加
  • UPDATE: 商品情報の変更、在庫数の調整
  • DELETE: 会員退会処理、期限切れデータの削除

それぞれの操作が連携して、一つのシステムを支えているのです。

課題

初心者が陥りがちな SQL 記述ミス

MySQL を学び始めた開発者が最も悩まされるのが、SQL 文の記述ミスです。構文エラーはもちろんのこと、動作はするものの期待した結果にならないケースが多発しています。

よく見られる記述ミスの例をご紹介しましょう。

mermaidflowchart LR
    subgraph mistake_types[よくある記述ミス]
        syntax[構文エラー]
        logic[論理エラー]
        performance[パフォーマンス問題]
        security[セキュリティリスク]
    end

    syntax --> syntax_ex["- セミコロン忘れ<br>- クォート不一致<br>- カラム名の誤記"]
    logic --> logic_ex["- WHERE句の条件ミス<br>- JOIN条件の間違い<br>- NULL値の扱い"]
    performance --> perf_ex["- インデックス未使用<br>- 不要なデータ取得<br>- N+1問題"]
    security --> sec_ex["- SQLインジェクション<br>- 権限の過剰付与<br>- パスワード平文保存"]

これらのミスは、システムの不具合や重大なセキュリティホールにつながる可能性があります。

特に危険なのは、以下のような記述です:

sql-- 危険な例:WHERE句なしのUPDATE
UPDATE users SET password = 'new_password';
-- → 全ユーザーのパスワードが変更されてしまう

このような単純なミスが、本番環境で大きな問題を引き起こすことがあります。

パフォーマンスを考慮しない非効率な書き方

「動けばいい」という考えで SQL 文を書いてしまうと、パフォーマンスの問題に直面することになります。小規模なデータでは気づかなくても、データ量が増加すると急激に処理速度が低下してしまうのです。

非効率な書き方の典型例を見てみましょう:

sql-- 非効率な例1:インデックスを活用していない検索
SELECT * FROM products WHERE UPPER(name) LIKE '%商品%';
-- → name列にインデックスがあっても使用されない

-- 非効率な例2:必要以上のデータを取得
SELECT * FROM orders WHERE created_at >= '2023-01-01';
-- → 全カラム取得で不要なデータも含んでしまう

このような書き方をしていると、以下のような問題が発生します:

  • データベースサーバーの負荷増大
  • アプリケーションの応答時間悪化
  • 同時接続ユーザー数の制限
  • サーバーコストの増加

セキュリティリスクを伴う危険な記述方法

最も深刻な問題は、セキュリティを考慮していない SQL 記述です。特に SQL インジェクション攻撃は、適切な対策を行わないと重大な情報漏洩につながります。

危険な記述パターンとその対策を整理してみましょう:

危険なパターンリスク影響度
動的 SQL 文字列結合SQL インジェクション極大
権限の過剰付与不正アクセス
パスワードの平文保存情報漏洩
エラー情報の詳細表示情報漏洩

特に以下のような書き方は絶対に避けるべきです:

sql-- 危険な例:SQLインジェクションの脆弱性
SET @sql = CONCAT('SELECT * FROM users WHERE name = "', user_input, '"');
PREPARE stmt FROM @sql;
EXECUTE stmt;
-- → user_inputに悪意のあるSQL文が含まれる可能性

解決策

SELECT 文の正しい書き方

SELECT 文は、データベースからデータを取得するための基本的なコマンドです。効率的で安全な SELECT 文を書くことで、アプリケーションのパフォーマンスを大幅に改善できます。

基本構文とオプション

まずは SELECT 文の基本構文を確認しましょう。

sql-- SELECT文の基本構文
SELECT column1, column2, ...
FROM table_name
WHERE condition
ORDER BY column_name
LIMIT number;

重要なポイントは、必要なカラムのみを指定することです。以下の例を比較してみてください:

sql-- 悪い例:全カラム取得
SELECT * FROM products;

-- 良い例:必要なカラムのみ取得
SELECT id, name, price FROM products;

後者の方が、以下の理由で優れています:

  • ネットワークトラフィックの削減
  • メモリ使用量の最適化
  • インデックスの効率的な活用
  • カラム構成変更時の影響回避

WHERE 条件の効率的な指定

WHERE 句は、取得するデータを絞り込むために使用します。効率的な条件指定のポイントを見ていきましょう。

sql-- インデックスを活用した検索
SELECT id, name, price
FROM products
WHERE category_id = 1
  AND price BETWEEN 1000 AND 5000
  AND status = 'active';

WHERE 句で注意すべき点は以下の通りです:

sql-- 避けるべき書き方1:関数を使った条件
SELECT * FROM orders WHERE YEAR(created_at) = 2023;

-- 推奨する書き方1:範囲指定
SELECT * FROM orders
WHERE created_at >= '2023-01-01'
  AND created_at < '2024-01-01';
sql-- 避けるべき書き方2:前方一致以外のLIKE
SELECT * FROM users WHERE name LIKE '%田中%';

-- 推奨する書き方2:前方一致のLIKE
SELECT * FROM users WHERE name LIKE '田中%';

JOIN を使った複数テーブル操作

実際の業務では、複数のテーブルを組み合わせてデータを取得することが多くあります。JOIN を正しく使うことで、効率的にデータを結合できます。

基本的な JOIN の種類を確認しましょう:

sql-- INNER JOIN:両方のテーブルに存在するデータのみ
SELECT
    u.id,
    u.name,
    p.name AS profile_name
FROM users u
INNER JOIN profiles p ON u.id = p.user_id;
sql-- LEFT JOIN:左側のテーブルの全データを取得
SELECT
    u.id,
    u.name,
    p.name AS profile_name
FROM users u
LEFT JOIN profiles p ON u.id = p.user_id;

複雑な JOIN の例も見てみましょう:

sql-- 3つのテーブルを結合した商品情報の取得
SELECT
    p.id,
    p.name,
    c.name AS category_name,
    s.stock_quantity
FROM products p
INNER JOIN categories c ON p.category_id = c.id
LEFT JOIN stocks s ON p.id = s.product_id
WHERE p.status = 'active'
  AND c.is_visible = 1
ORDER BY p.created_at DESC
LIMIT 20;

この例では、商品(products)、カテゴリ(categories)、在庫(stocks)の 3 つのテーブルを結合しています。

INSERT 文の正しい書き方

INSERT 文は、データベースに新しいレコードを追加するためのコマンドです。安全で効率的な INSERT 文の書き方をマスターしましょう。

単一レコード挿入

基本的な INSERT 文の構文は以下の通りです:

sql-- INSERT文の基本構文
INSERT INTO table_name (column1, column2, column3)
VALUES (value1, value2, value3);

実際の例を見てみましょう:

sql-- ユーザー情報の挿入
INSERT INTO users (name, email, password, created_at)
VALUES ('田中太郎', 'tanaka@example.com', 'hashed_password', NOW());

重要なポイントは、以下の通りです:

  1. カラム名の明示: INSERT 文では必ずカラム名を指定する
  2. データ型の一致: 各カラムのデータ型に合わせた値を設定する
  3. 必須カラムの確認: NOT NULL 制約のあるカラムは必ず値を設定する
sql-- 悪い例:カラム名を省略
INSERT INTO users VALUES ('田中太郎', 'tanaka@example.com');

-- 良い例:カラム名を明示
INSERT INTO users (name, email)
VALUES ('田中太郎', 'tanaka@example.com');

複数レコード一括挿入

大量のデータを挿入する場合は、一括挿入を使用することでパフォーマンスを大幅に改善できます。

sql-- 複数レコードの一括挿入
INSERT INTO products (name, price, category_id, created_at)
VALUES
    ('商品A', 1000, 1, NOW()),
    ('商品B', 1500, 1, NOW()),
    ('商品C', 2000, 2, NOW()),
    ('商品D', 2500, 2, NOW());

一括挿入の利点:

  • データベースへの接続回数削減
  • トランザクション処理の効率化
  • インデックス更新処理の最適化

ただし、一度に挿入するレコード数が多すぎると、以下の問題が発生する可能性があります:

sql-- 注意:一度に大量挿入する場合の対策
-- 1000件ずつに分割して挿入
INSERT INTO products (name, price, category_id, created_at)
VALUES
    -- 1-1000件目のデータ
    ('商品1', 1000, 1, NOW()),
    -- ... 998行省略
    ('商品1000', 1000, 1, NOW());

重複処理の対応方法

データ挿入時に重複が発生する場合の対処方法を確認しましょう。

ON DUPLICATE KEY UPDATE の使用:

sql-- 重複時は更新処理を実行
INSERT INTO user_stats (user_id, login_count, last_login)
VALUES (1, 1, NOW())
ON DUPLICATE KEY UPDATE
    login_count = login_count + 1,
    last_login = NOW();

INSERT IGNORE の使用:

sql-- 重複時はエラーを発生させずスキップ
INSERT IGNORE INTO tags (name, created_at)
VALUES ('MySQL', NOW());

REPLACE の使用:

sql-- 重複時は既存レコードを削除して新規挿入
REPLACE INTO user_preferences (user_id, theme, language)
VALUES (1, 'dark', 'ja');

それぞれの使い分けは以下の通りです:

方法使用場面特徴
ON DUPLICATE KEY UPDATEカウンターなど累積的な更新柔軟な更新処理が可能
INSERT IGNORE重複を単純に無視したい場合シンプルな記述
REPLACE既存データを完全に置き換えDELETE + INSERT の動作

UPDATE 文の正しい書き方

UPDATE 文は、既存のレコードの内容を変更するためのコマンドです。間違った使い方をすると、重要なデータを破損してしまう可能性があるため、特に注意深く扱う必要があります。

安全な更新処理の書き方

UPDATE 文の基本構文は以下の通りです:

sql-- UPDATE文の基本構文
UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;

最も重要なのは、WHERE 句を必ず指定することです:

sql-- 良い例:WHERE句で対象を限定
UPDATE users
SET last_login = NOW(), login_count = login_count + 1
WHERE id = 1;
sql-- 危険な例:WHERE句なし(全レコードが更新される)
UPDATE users
SET password = 'reset123';
-- → データベース内の全ユーザーのパスワードが変更される

安全な更新処理のチェックリストを作成しましょう:

  1. WHERE 句の必須確認: 対象レコードを必ず限定する
  2. 更新前の確認: SELECT で対象データを確認する
  3. バックアップの取得: 重要な更新前はバックアップを取る
  4. テスト環境での検証: 本番環境での実行前に動作確認する
sql-- 更新前の確認
SELECT id, name, email, status
FROM users
WHERE status = 'inactive' AND last_login < '2023-01-01';

-- 確認後に更新実行
UPDATE users
SET status = 'dormant', updated_at = NOW()
WHERE status = 'inactive' AND last_login < '2023-01-01';

条件指定の重要性

UPDATE 文では、WHERE 句の条件指定が極めて重要です。複雑な条件を設定する際のポイントを確認しましょう。

sql-- 複数条件を組み合わせた更新
UPDATE products
SET
    price = price * 0.9,  -- 10%割引
    discount_flag = 1,
    updated_at = NOW()
WHERE
    category_id IN (1, 2, 3)  -- 特定カテゴリのみ
    AND stock_quantity > 0    -- 在庫あり
    AND created_at < '2023-01-01'  -- 古い商品
    AND status = 'active';    -- アクティブな商品のみ

条件指定時の注意点:

sql-- 注意:NULL値を含む条件
-- 悪い例
UPDATE users SET status = 'verified' WHERE phone IS NOT NULL;

-- 良い例:NULL値を適切に処理
UPDATE users
SET status = 'verified'
WHERE phone IS NOT NULL AND phone != '';

トランザクションとの組み合わせ

重要な更新処理では、トランザクションを使用して処理の整合性を保つことが重要です。

sql-- トランザクションを使った安全な更新処理
START TRANSACTION;

-- 在庫の確認
SELECT stock_quantity FROM products WHERE id = 1;

-- 在庫が十分な場合のみ更新
UPDATE products
SET stock_quantity = stock_quantity - 1
WHERE id = 1 AND stock_quantity > 0;

-- 注文レコードの作成
INSERT INTO orders (product_id, quantity, user_id, created_at)
VALUES (1, 1, 100, NOW());

-- 処理が成功した場合はコミット
COMMIT;

-- エラーが発生した場合はロールバック
-- ROLLBACK;

複数テーブルの更新を伴う場合の例:

sqlSTART TRANSACTION;

-- ユーザーのポイント減算
UPDATE users
SET points = points - 100
WHERE id = 1 AND points >= 100;

-- ポイント使用履歴の記録
INSERT INTO point_history (user_id, points, action, created_at)
VALUES (1, -100, 'purchase', NOW());

-- 商品の購入処理
INSERT INTO purchases (user_id, product_id, points_used, created_at)
VALUES (1, 10, 100, NOW());

COMMIT;

DELETE 文の正しい書き方

DELETE 文は、データベースからレコードを削除するためのコマンドです。削除されたデータは基本的に復元できないため、最も慎重に扱う必要があります。

誤削除防止のベストプラクティス

DELETE 文の基本構文は以下の通りです:

sql-- DELETE文の基本構文
DELETE FROM table_name
WHERE condition;

最重要ルール:DELETE 文では必ず WHERE 句を指定する

sql-- 良い例:WHERE句で削除対象を限定
DELETE FROM users
WHERE status = 'deleted' AND last_login < '2022-01-01';
sql-- 絶対に避けるべき例:WHERE句なし
DELETE FROM users;
-- → テーブル内の全データが削除される

安全な削除処理の手順:

  1. 削除前の確認: SELECT で削除対象を確認
  2. 件数の確認: 削除される件数をチェック
  3. バックアップの取得: 重要なデータの場合は事前にバックアップ
  4. 段階的削除: 大量データの場合は分割して削除
sql-- ステップ1: 削除対象の確認
SELECT COUNT(*) FROM users
WHERE status = 'inactive' AND last_login < '2022-01-01';

-- ステップ2: 実際のデータ確認
SELECT id, name, email, last_login
FROM users
WHERE status = 'inactive' AND last_login < '2022-01-01'
LIMIT 10;

-- ステップ3: 削除実行
DELETE FROM users
WHERE status = 'inactive' AND last_login < '2022-01-01';

物理削除と論理削除の使い分け

削除処理には「物理削除」と「論理削除」の 2 つのアプローチがあります。適切な使い分けが重要です。

物理削除(実際にレコードを削除):

sql-- 物理削除の例
DELETE FROM temp_data
WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 DAY);

論理削除(削除フラグを設定):

sql-- 論理削除の例
UPDATE users
SET
    deleted_at = NOW(),
    status = 'deleted'
WHERE id = 1;

使い分けの基準:

削除方式使用場面メリットデメリット
物理削除一時的なデータ、ログデータ容量削減、シンプル復元不可
論理削除ユーザーデータ、重要な業務データ復元可能、監査証跡容量増加、クエリ複雑化

論理削除を使用する場合は、通常の SELECT 文で削除済みデータを除外する必要があります:

sql-- 論理削除対応のSELECT文
SELECT id, name, email
FROM users
WHERE deleted_at IS NULL;  -- 削除されていないデータのみ取得

バックアップとの連携

重要なデータを削除する前は、必ずバックアップを取得しましょう。

sql-- 削除前のバックアップ作成
CREATE TABLE users_backup_20241201 AS
SELECT * FROM users
WHERE status = 'inactive' AND last_login < '2022-01-01';

-- バックアップ確認
SELECT COUNT(*) FROM users_backup_20241201;

-- 実際の削除実行
DELETE FROM users
WHERE status = 'inactive' AND last_login < '2022-01-01';

大量データの削除では、分割処理を行います:

sql-- 大量削除の分割処理
DELETE FROM log_data
WHERE created_at < '2023-01-01'
LIMIT 1000;

-- 上記を必要な回数繰り返す
-- システムへの負荷を分散させる

具体例

実際の業務で使用するサンプルデータベース

実際の開発現場でよく見られる EC サイトのデータベース構造を例に、4 つの基本操作を実践的に学習していきましょう。

まずは、サンプルデータベースの構造を確認します:

mermaiderDiagram
    USERS {
        int id PK
        varchar name
        varchar email UK
        varchar password
        datetime created_at
        datetime updated_at
        datetime deleted_at
    }

    PRODUCTS {
        int id PK
        varchar name
        text description
        decimal price
        int category_id FK
        int stock_quantity
        enum status
        datetime created_at
        datetime updated_at
    }

    CATEGORIES {
        int id PK
        varchar name
        varchar slug UK
        boolean is_visible
        int sort_order
    }

    ORDERS {
        int id PK
        int user_id FK
        decimal total_amount
        enum status
        datetime created_at
        datetime updated_at
    }

    ORDER_ITEMS {
        int id PK
        int order_id FK
        int product_id FK
        int quantity
        decimal price
    }

    USERS ||--o{ ORDERS : "places"
    PRODUCTS }o--|| CATEGORIES : "belongs to"
    ORDERS ||--o{ ORDER_ITEMS : "contains"
    PRODUCTS ||--o{ ORDER_ITEMS : "included in"

このデータベース構造を使って、実際の業務シナリオに沿った SQL 操作を見ていきましょう。

ケーススタディごとの実装例

ケーススタディ 1: 商品一覧の表示機能

要件: カテゴリ別の商品一覧を表示し、在庫があるもののみを表示する

sql-- 商品一覧取得のSELECT文
SELECT
    p.id,
    p.name,
    p.price,
    p.stock_quantity,
    c.name AS category_name
FROM products p
INNER JOIN categories c ON p.category_id = c.id
WHERE
    p.status = 'active'
    AND p.stock_quantity > 0
    AND c.is_visible = 1
ORDER BY
    c.sort_order ASC,
    p.created_at DESC
LIMIT 20;

ポイント解説:

  • INNERJOIN でカテゴリ情報を結合
  • WHERE 句で表示条件を適切に設定
  • ORDER BY でユーザビリティを考慮した並び順を指定
  • LIMIT でページング処理に対応

ケーススタディ 2: 新規会員登録機能

要件: 新しいユーザーを安全に登録し、重複メールアドレスをチェック

sql-- 重複チェック付きユーザー登録
INSERT INTO users (name, email, password, created_at, updated_at)
SELECT
    '田中太郎' AS name,
    'tanaka@example.com' AS email,
    SHA2('user_password_123', 256) AS password,
    NOW() AS created_at,
    NOW() AS updated_at
WHERE NOT EXISTS (
    SELECT 1 FROM users
    WHERE email = 'tanaka@example.com'
    AND deleted_at IS NULL
);

ポイント解説:

  • NOT EXISTS で重複チェックを実装
  • SHA2 関数でパスワードをハッシュ化
  • 論理削除(deleted_at)を考慮したチェック

ケーススタディ 3: 注文処理機能

要件: 注文データの作成と在庫数の更新をトランザクションで安全に処理

sql-- 注文処理のトランザクション
START TRANSACTION;

-- 在庫確認と更新
UPDATE products
SET
    stock_quantity = stock_quantity - 2,
    updated_at = NOW()
WHERE
    id = 1
    AND stock_quantity >= 2
    AND status = 'active';

-- 更新行数をチェック(実際のアプリケーションではROW_COUNT()を使用)
-- IF ROW_COUNT() = 0 THEN ROLLBACK;

-- 注文レコード作成
INSERT INTO orders (user_id, total_amount, status, created_at, updated_at)
VALUES (1, 3000, 'pending', NOW(), NOW());

-- 注文IDを取得(実際のアプリケーションではLAST_INSERT_ID()を使用)
SET @order_id = LAST_INSERT_ID();

-- 注文アイテム作成
INSERT INTO order_items (order_id, product_id, quantity, price)
VALUES (@order_id, 1, 2, 1500);

COMMIT;

ポイント解説:

  • トランザクションで整合性を保証
  • 在庫数の原子的な更新
  • LAST_INSERT_ID()で生成された ID を取得

ケーススタディ 4: 商品情報の一括更新

要件: 特定カテゴリの商品価格を一括で 10%値上げする

sql-- 価格更新前の確認
SELECT
    p.id,
    p.name,
    p.price AS current_price,
    ROUND(p.price * 1.1, 0) AS new_price,
    c.name AS category_name
FROM products p
INNER JOIN categories c ON p.category_id = c.id
WHERE c.slug = 'electronics'
  AND p.status = 'active';

-- 実際の価格更新
UPDATE products p
INNER JOIN categories c ON p.category_id = c.id
SET
    p.price = ROUND(p.price * 1.1, 0),
    p.updated_at = NOW()
WHERE
    c.slug = 'electronics'
    AND p.status = 'active';

ポイント解説:

  • JOIN を使った UPDATE 文
  • ROUND 関数で価格を適切に処理
  • 更新前の確認クエリで安全性を確保

ケーススタディ 5: 古いデータの削除

要件: 1 年以上前のキャンセル済み注文を論理削除する

sql-- 削除対象の確認
SELECT
    COUNT(*) AS delete_count,
    MIN(created_at) AS oldest_date,
    MAX(created_at) AS newest_date
FROM orders
WHERE
    status = 'cancelled'
    AND created_at < DATE_SUB(NOW(), INTERVAL 1 YEAR);

-- 論理削除の実行
UPDATE orders
SET
    deleted_at = NOW(),
    updated_at = NOW()
WHERE
    status = 'cancelled'
    AND created_at < DATE_SUB(NOW(), INTERVAL 1 YEAR)
    AND deleted_at IS NULL;

ポイント解説:

  • 論理削除によるデータ保全
  • DATE_SUB 関数で期間指定
  • 削除済みデータの重複処理を防止

エラーパターンと解決方法

実際の開発では、様々なエラーに遭遇します。よくあるエラーパターンと解決方法を確認しましょう。

エラーパターン 1: 外部キー制約違反

エラーコード: Error 1452: Cannot add or update a child row: a foreign key constraint fails

sql-- エラーの例:存在しないカテゴリIDを指定
INSERT INTO products (name, price, category_id)
VALUES ('新商品', 1500, 999);  -- category_id = 999 が存在しない

解決方法:

sql-- 外部キーの存在確認
SELECT id FROM categories WHERE id = 999;

-- 正しいカテゴリIDで再実行
INSERT INTO products (name, price, category_id)
VALUES ('新商品', 1500, 1);  -- 存在するcategory_id

エラーパターン 2: 重複キー違反

エラーコード: Error 1062: Duplicate entry 'user@example.com' for key 'email'

sql-- エラーの例:重複するメールアドレスでの登録
INSERT INTO users (name, email)
VALUES ('山田花子', 'user@example.com');  -- 既存のメールアドレス

解決方法:

sql-- ON DUPLICATE KEY UPDATEを使用した対応
INSERT INTO users (name, email, updated_at)
VALUES ('山田花子', 'user@example.com', NOW())
ON DUPLICATE KEY UPDATE
    name = VALUES(name),
    updated_at = NOW();

エラーパターン 3: データ型不一致

エラーコード: Error 1366: Incorrect integer value

sql-- エラーの例:文字列を数値カラムに挿入
UPDATE products SET price = 'thousand' WHERE id = 1;

解決方法:

sql-- 適切なデータ型で更新
UPDATE products SET price = 1000 WHERE id = 1;

-- 文字列からの変換が必要な場合
UPDATE products
SET price = CAST(REPLACE(price_text, ',', '') AS DECIMAL(10,2))
WHERE id = 1;

まとめ

MySQL の基本操作(SELECT・INSERT・UPDATE・DELETE)について、初心者の方でも安心して使える正しい書き方を詳しく解説してまいりました。

重要なポイントを改めて整理いたします:

SELECT 文のポイント

  • 必要なカラムのみを指定してパフォーマンスを最適化
  • WHERE 句でインデックスを効率的に活用
  • JOIN を使った複数テーブル操作をマスター

INSERT 文のポイント

  • カラム名を明示して安全性を確保
  • 一括挿入でパフォーマンスを向上
  • 重複処理を適切に処理

UPDATE 文のポイント

  • WHERE 句を必ず指定して誤更新を防止
  • トランザクションで整合性を保証
  • 更新前の確認を習慣化

DELETE 文のポイント

  • 物理削除と論理削除を適切に使い分け
  • バックアップとの連携で安全性を確保
  • 段階的削除で大量データに対応

これらの基本操作を正しく理解することで、安全で効率的なデータベース操作ができるようになります。最初は慎重すぎるくらいでちょうどよいですので、一つひとつの操作を丁寧に確認しながら実践してください。

実際の業務では、これらの基本操作を組み合わせて複雑な処理を実現することになります。今回学んだ基礎をしっかりと身につけることで、より高度な SQL 文も安心して書けるようになることでしょう。

関連リンク