SQL チートシート

目的別 SQL クイックリファレンス

データ検索 (SELECT)

テーブルから情報を取得するための基本的な操作です。

基本的な検索

  • 全ての列を取得:
    
    SELECT * FROM テーブル名;
                    
  • 特定の列を取得:
    
    SELECT1,2 FROM テーブル名;
                    
  • 重複を除外して取得 (DISTINCT):
    
    SELECT DISTINCT1 FROM テーブル名;
                    
  • 別名 (エイリアス) を使用:
    
    SELECT1 AS 別名1,2 AS 別名2 FROM テーブル名;
    SELECT t.1, t.2 FROM テーブル名 AS t; -- テーブルにも別名
                    

条件指定 (WHERE)

特定の条件に一致する行のみを取得します。

  • 基本的な比較演算子: `=`, `<>` (または `!=`), `<`, `>`, `<=`, `>=`
    
    SELECT1,2 FROM テーブル名 WHERE1 = '値';
    SELECT1,2 FROM テーブル名 WHERE2 > 100;
                    
  • 論理演算子 (AND, OR, NOT):
    
    SELECT * FROM テーブル名 WHERE1 = '値1' AND2 < 50;
    SELECT * FROM テーブル名 WHERE1 = '値1' OR1 = '値2';
    SELECT * FROM テーブル名 WHERE NOT1 = '特定の値';
                    
  • 範囲指定 (BETWEEN):
    
    SELECT * FROM テーブル名 WHERE1 BETWEEN 10 AND 20; -- 10と20を含む
                    
  • リスト指定 (IN):
    
    SELECT * FROM テーブル名 WHERE1 IN ('値A', '値B', '値C');
                    
  • パターンマッチング (LIKE): `%` (任意の文字列), `_` (任意の1文字)
    
    SELECT * FROM テーブル名 WHERE1 LIKE 'A%'; -- Aで始まる
    SELECT * FROM テーブル名 WHERE1 LIKE '%パターン%'; -- パターンを含む
    SELECT * FROM テーブル名 WHERE1 LIKE 'A_C'; -- Aで始まり、Cで終わる3文字
                    

    注意: エスケープ文字はデータベースによって異なる場合があります (例: `\`)

  • NULL 値の判定 (IS NULL, IS NOT NULL):
    
    SELECT * FROM テーブル名 WHERE1 IS NULL;
    SELECT * FROM テーブル名 WHERE1 IS NOT NULL;
                    

結果の並び替え (ORDER BY)

取得した結果を指定した列で並び替えます。

  • 昇順 (ASC – デフォルト):
    
    SELECT * FROM テーブル名 ORDER BY1 ASC;
    SELECT * FROM テーブル名 ORDER BY1; -- ASCは省略可能
                    
  • 降順 (DESC):
    
    SELECT * FROM テーブル名 ORDER BY1 DESC;
                    
  • 複数列での並び替え:
    
    SELECT * FROM テーブル名 ORDER BY1 ASC,2 DESC;
                    
  • 列番号での指定 (非推奨だが可能):
    
    SELECT1,2 FROM テーブル名 ORDER BY 1 DESC; -- 1番目の列(列1)で降順ソート
                    

結果の制限 (LIMIT / TOP / ROWNUM)

取得する行数を制限します。構文はデータベース製品によって異なります。

データベース 構文例 (先頭からN件) 構文例 (M行目からN件)
MySQL, PostgreSQL, SQLite
SELECT * FROM テーブル名 LIMIT N;
SELECT * FROM テーブル名 LIMIT N OFFSET M; -- Mは0始まり
SQL Server
SELECT TOP N * FROM テーブル名;
SELECT * FROM テーブル名 ORDER BY 主キー OFFSET M ROWS FETCH NEXT N ROWS ONLY; -- SQL Server 2012以降
Oracle
SELECT * FROM テーブル名 WHERE ROWNUM <= N; -- ORDER BYとの併用注意
SELECT * FROM ( SELECT t.*, ROWNUM AS rn FROM ( SELECT * FROM テーブル名 ORDER BY 主キー ) t ) WHERE rn BETWEEN M+1 AND M+N; -- Oracle 12c より前
SELECT * FROM テーブル名 ORDER BY 主キー OFFSET M ROWS FETCH NEXT N ROWS ONLY; -- Oracle 12c以降

集計関数とグループ化 (Aggregate Functions, GROUP BY, HAVING)

データをグループ化し、各グループに対して集計を行います。

  • 主な集計関数:
    • `COUNT()`: 行数を数える ( `COUNT(*)`: 全行数, `COUNT(列名)`: NULL以外の行数, `COUNT(DISTINCT 列名)`: 重複を除いた行数)
    • `SUM(列名)`: 合計値
    • `AVG(列名)`: 平均値
    • `MAX(列名)`: 最大値
    • `MIN(列名)`: 最小値
    
    SELECT COUNT(*) AS 総行数, AVG(価格) AS 平均価格 FROM 商品;
                    
  • グループ化 (GROUP BY): 特定の列の値が同じ行をグループ化し、集計関数を適用します。`SELECT`句には`GROUP BY`で指定した列か集計関数しか記述できません。
    
    SELECT カテゴリID, COUNT(*) AS 商品数
    FROM 商品
    GROUP BY カテゴリID;
                    
  • グループ化後の条件指定 (HAVING): `GROUP BY`でグループ化された結果に対して条件を指定します。`WHERE`句はグループ化前の行に対する条件指定です。
    
    SELECT カテゴリID, AVG(価格) AS 平均価格
    FROM 商品
    GROUP BY カテゴリID
    HAVING AVG(価格) > 5000; -- 平均価格が5000より大きいカテゴリのみ
                    

テーブル結合 (JOIN)

複数のテーブルを関連する列を基に結合します。

JOINの種類 説明 構文例
INNER JOIN (または JOIN) 両方のテーブルに結合キーが存在する行のみを結合します。
SELECT t1.*, t2.*
FROM テーブル1 t1
INNER JOIN テーブル2 t2 ON t1.結合キー = t2.結合キー;
LEFT JOIN (または LEFT OUTER JOIN) 左側のテーブル(t1)の全ての行と、右側のテーブル(t2)で結合キーが一致する行を結合します。一致しない場合は右側の列はNULLになります。
SELECT t1.*, t2.*
FROM テーブル1 t1
LEFT JOIN テーブル2 t2 ON t1.結合キー = t2.結合キー;
RIGHT JOIN (または RIGHT OUTER JOIN) 右側のテーブル(t2)の全ての行と、左側のテーブル(t1)で結合キーが一致する行を結合します。一致しない場合は左側の列はNULLになります。
SELECT t1.*, t2.*
FROM テーブル1 t1
RIGHT JOIN テーブル2 t2 ON t1.結合キー = t2.結合キー;
FULL OUTER JOIN 左右両方のテーブルの全ての行を結合します。どちらかのテーブルにしか存在しない場合は、存在しない側の列はNULLになります。(MySQLは標準ではサポートしていません)
SELECT t1.*, t2.*
FROM テーブル1 t1
FULL OUTER JOIN テーブル2 t2 ON t1.結合キー = t2.結合キー;
CROSS JOIN 両方のテーブルの行の全ての組み合わせ(デカルト積)を生成します。結合条件は指定しません。
SELECT t1.*, t2.*
FROM テーブル1 t1
CROSS JOIN テーブル2 t2;
SELF JOIN 同じテーブル同士を結合します。テーブルに別名をつける必要があります。
SELECT e1.名前 AS 社員名, e2.名前 AS 上司名
FROM 従業員 e1
LEFT JOIN 従業員 e2 ON e1.上司ID = e2.従業員ID;

副問い合わせ (Subquery)

クエリの中に別のクエリを埋め込む方法です。

  • SELECT句内の副問い合わせ (スカラ副問い合わせ): 単一の値を返す必要があります。
    
    SELECT
      商品名,
      価格,
      (SELECT AVG(価格) FROM 商品) AS 全体平均価格
    FROM 商品;
                    
  • FROM句内の副問い合わせ (インラインビュー): 結果セットを一時的なテーブルとして扱います。
    
    SELECT t.カテゴリID, t.平均価格
    FROM (
      SELECT カテゴリID, AVG(価格) AS 平均価格
      FROM 商品
      GROUP BY カテゴリID
    ) AS t
    WHERE t.平均価格 > 5000;
                    
  • WHERE句内の副問い合わせ:
    • 単一値を返す副問い合わせ: 比較演算子 (`=`, `>`, etc.) と共に使用します。
      
      SELECT 商品名, 価格 FROM 商品
      WHERE 価格 > (SELECT AVG(価格) FROM 商品);
                              
    • リストを返す副問い合わせ: `IN`, `NOT IN` と共に使用します。
      
      SELECT * FROM 注文
      WHERE 顧客ID IN (SELECT 顧客ID FROM 顧客 WHERE 地域 = '東京');
                              
    • 存在確認: `EXISTS`, `NOT EXISTS` と共に使用します。副問い合わせが1行でも返せば真。
      
      SELECT * FROM 顧客 c
      WHERE EXISTS (SELECT 1 FROM 注文 o WHERE o.顧客ID = c.顧客ID); -- 注文履歴のある顧客
                              
    • 比較演算子 (`ANY`, `SOME`, `ALL`) と共に使用します。
      
      -- いずれかの東京の顧客の注文額より大きい注文
      SELECT * FROM 注文
      WHERE 金額 > ANY (SELECT 注文額 FROM 注文履歴 WHERE 顧客地域 = '東京');
      -- 全ての東京の顧客の注文額より大きい注文
      SELECT * FROM 注文
      WHERE 金額 > ALL (SELECT 注文額 FROM 注文履歴 WHERE 顧客地域 = '東京');
                              
  • 相関副問い合わせ (Correlated Subquery): 外側のクエリの列を内側の副問い合わせが参照するものです。外側のクエリの行ごとに実行されるため、パフォーマンスに影響が出ることがあります。
    
    -- 各カテゴリで最も価格が高い商品
    SELECT 商品名, カテゴリID, 価格
    FROM 商品 p1
    WHERE 価格 = (SELECT MAX(価格) FROM 商品 p2 WHERE p1.カテゴリID = p2.カテゴリID);
                    

ウィンドウ関数 (Window Functions)

行のセット(ウィンドウ)に対して計算を行いますが、`GROUP BY`のように行を集約しません。各行に対して計算結果を返します。分析関数とも呼ばれます。

`関数名() OVER ( [PARTITION BY 列…] [ORDER BY 列…] [ROWS BETWEEN … AND …] )` の形式で使用します。

  • ランキング関数:
    • `ROW_NUMBER()`: ウィンドウ内で一意の連番を付与 (同順位でも異なる番号)
    • `RANK()`: 順位を付与 (同順位は同じ番号、次の順位は飛ぶ)
    • `DENSE_RANK()`: 順位を付与 (同順位は同じ番号、次の順位は飛ばない)
    • `NTILE(n)`: ウィンドウをn個のグループに分割し、グループ番号を付与
    
    SELECT
      商品名,
      価格,
      カテゴリID,
      ROW_NUMBER() OVER (PARTITION BY カテゴリID ORDER BY 価格 DESC) AS カテゴリ内価格順位_ROWNUM,
      RANK()       OVER (PARTITION BY カテゴリID ORDER BY 価格 DESC) AS カテゴリ内価格順位_RANK,
      DENSE_RANK() OVER (PARTITION BY カテゴリID ORDER BY 価格 DESC) AS カテゴリ内価格順位_DENSERANK
    FROM 商品;
                    
  • 集計関数 (ウィンドウ関数として使用): `SUM()`, `AVG()`, `COUNT()`, `MAX()`, `MIN()` など
    
    SELECT
      注文日,
      注文額,
      SUM(注文額) OVER (ORDER BY 注文日) AS 累計注文額, -- 全体の累計
      AVG(注文額) OVER (PARTITION BY MONTH(注文日)) AS 月別平均注文額 -- 月ごとの平均
    FROM 注文履歴;
                    
  • 値関数:
    • `LAG(列 [, オフセット [, デフォルト値]])`: ウィンドウ内の前の行の値を取得
    • `LEAD(列 [, オフセット [, デフォルト値]])`: ウィンドウ内の後の行の値を取得
    • `FIRST_VALUE(列)`: ウィンドウ内の最初の行の値を取得
    • `LAST_VALUE(列)`: ウィンドウ内の最後の行の値を取得
    
    SELECT
      注文日,
      注文額,
      LAG(注文額, 1, 0) OVER (ORDER BY 注文日) AS 前日の注文額,
      LEAD(注文額, 1, 0) OVER (ORDER BY 注文日) AS 翌日の注文額
    FROM 注文履歴;
                    
  • フレーム句 (ROWS/RANGE BETWEEN): ウィンドウ関数が計算対象とする範囲をより細かく指定します。
    • `ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW`: 先頭行から現在の行まで (累計計算のデフォルト)
    • `ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING`: 前の行、現在の行、次の行
    • `ROWS BETWEEN 3 PRECEDING AND CURRENT ROW`: 3つ前の行から現在の行まで (移動平均など)
    
    SELECT
      日付,
      売上,
      AVG(売上) OVER (ORDER BY 日付 ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS 3日間移動平均
    FROM 日次売上;
                    

共通テーブル式 (Common Table Expression – CTE)

`WITH`句を使って、クエリ内で一時的な名前付き結果セットを定義します。複雑なクエリを読みやすくしたり、再帰的なクエリを記述するのに役立ちます。

  • 基本的な使い方:
    
    WITH CategorySales AS (
        SELECT
            p.カテゴリID,
            SUM(oi.数量 * oi.単価) AS カテゴリ別売上
        FROM 商品 p
        JOIN 注文明細 oi ON p.商品ID = oi.商品ID
        GROUP BY p.カテゴリID
    ), HighSalesCategories AS (
        SELECT カテゴリID
        FROM CategorySales
        WHERE カテゴリ別売上 > 100000
    )
    SELECT
        c.カテゴリ名,
        cs.カテゴリ別売上
    FROM カテゴリ c
    JOIN CategorySales cs ON c.カテゴリID = cs.カテゴリID
    WHERE c.カテゴリID IN (SELECT カテゴリID FROM HighSalesCategories);
                    
  • 再帰CTE (Recursive CTE): 階層構造データ(組織図、親子関係など)を扱う際に有用です。`WITH RECURSIVE` (PostgreSQL, MySQL 8.0+) または `WITH` (SQL Server, Oracle) を使用します。
    
    -- 例: 従業員とその上司の階層を取得 (SQL Server/Oracle)
    WITH EmployeeHierarchy (従業員ID, 名前, 上司ID, Level) AS (
        -- アンカーメンバー (起点となる行)
        SELECT 従業員ID, 名前, 上司ID, 0
        FROM 従業員
        WHERE 上司ID IS NULL -- 最上位の従業員
    
        UNION ALL
    
        -- 再帰メンバー (アンカーメンバーに結合)
        SELECT e.従業員ID, e.名前, e.上司ID, eh.Level + 1
        FROM 従業員 e
        INNER JOIN EmployeeHierarchy eh ON e.上司ID = eh.従業員ID
    )
    SELECT * FROM EmployeeHierarchy ORDER BY Level, 従業員ID;
                    

データ操作 (DML – Data Manipulation Language)

テーブル内のデータを追加、更新、削除します。

データ挿入 (INSERT)

  • 1行挿入 (列指定):
    
    INSERT INTO テーブル名 (1,2,3) VALUES (1,2,3);
                    
  • 1行挿入 (全列指定 – 非推奨): 列の順序に依存するため、列指定が推奨されます。
    
    INSERT INTO テーブル名 VALUES (全列分の値...);
                    
  • 複数行挿入 (標準SQL / PostgreSQL / MySQLなど):
    
    INSERT INTO テーブル名 (1,2) VALUES
    (1A,2A),
    (1B,2B),
    (1C,2C);
                    
  • 複数行挿入 (Oracle / SQL Server – UNION ALL を使用):
    
    -- Oracle
    INSERT ALL
      INTO テーブル名 (1,2) VALUES (1A,2A)
      INTO テーブル名 (1,2) VALUES (1B,2B)
    SELECT * FROM dual;
    
    -- SQL Server (昔の方法)
    INSERT INTO テーブル名 (1,2)
    SELECT1A,2A
    UNION ALL
    SELECT1B,2B;
                    

    注意: SQL Server 2008以降、MySQL/PostgreSQL と同様の VALUES 句による複数行挿入も可能です。

  • 別のテーブルから挿入 (INSERT INTO … SELECT):
    
    INSERT INTO テーブルA (1,2)
    SELECT 列X, 列Y FROM テーブルB WHERE 条件;
                    
  • 存在しない場合のみ挿入 (UPSERT / MERGE): データベースによって構文が異なります。
    • MySQL: `INSERT … ON DUPLICATE KEY UPDATE`
      
      INSERT INTO テーブル名 (ID,1,2) VALUES (1, '値A', '値B')
      ON DUPLICATE KEY UPDATE1 = '新しい値A',2 = '新しい値B';
                              
    • PostgreSQL: `INSERT … ON CONFLICT DO UPDATE / DO NOTHING`
      
      -- 更新する場合
      INSERT INTO テーブル名 (ID,1,2) VALUES (1, '値A', '値B')
      ON CONFLICT (ID) DO UPDATE SET1 = EXCLUDED.1,2 = EXCLUDED.2;
      -- 何もしない場合
      INSERT INTO テーブル名 (ID,1,2) VALUES (1, '値A', '値B')
      ON CONFLICT (ID) DO NOTHING;
                              
    • SQL Server / Oracle: `MERGE`
      
      MERGE INTO ターゲットテーブル T
      USING ソーステーブル S ON (T.結合キー = S.結合キー)
      WHEN MATCHED THEN
          UPDATE SET T.1 = S.1, T.2 = S.2
      WHEN NOT MATCHED THEN
          INSERT (結合キー,1,2) VALUES (S.結合キー, S.1, S.2);
                              
    • SQLite: `INSERT OR REPLACE INTO` または `INSERT OR IGNORE INTO`
      
      INSERT OR REPLACE INTO テーブル名 (ID,1,2) VALUES (1, '値A', '値B'); -- 存在すれば置き換え
      INSERT OR IGNORE INTO テーブル名 (ID,1,2) VALUES (1, '値A', '値B'); -- 存在すれば無視
                              

データ更新 (UPDATE)

  • 特定の行を更新: `WHERE`句で対象行を指定します。指定しないと全行が更新されます。
    
    UPDATE テーブル名
    SET1 = 新しい値1,2 = 新しい値2
    WHERE 条件;
                    
  • 他のテーブルの値を使って更新 (データベースによる違いあり):
    • 標準SQL / PostgreSQL / SQL Server: `FROM`句や`JOIN`を使用
      
      -- SQL Server
      UPDATE t1
      SET t1.列A = t2.列X
      FROM テーブル1 t1
      INNER JOIN テーブル2 t2 ON t1.結合キー = t2.結合キー
      WHERE t1.条件;
      
      -- PostgreSQL
      UPDATE テーブル1 t1
      SET 列A = t2.列X
      FROM テーブル2 t2
      WHERE t1.結合キー = t2.結合キー AND t1.条件;
                              
    • MySQL: `JOIN`を`UPDATE`句の後ろに記述
      
      UPDATE テーブル1 t1
      INNER JOIN テーブル2 t2 ON t1.結合キー = t2.結合キー
      SET t1.列A = t2.列X
      WHERE t1.条件;
                              
    • Oracle: 副問い合わせや`MERGE`を使用
      
      -- 副問い合わせ
      UPDATE テーブル1 t1
      SET 列A = (SELECT t2.列X FROM テーブル2 t2 WHERE t1.結合キー = t2.結合キー)
      WHERE EXISTS (SELECT 1 FROM テーブル2 t2 WHERE t1.結合キー = t2.結合キー)
      AND t1.条件;
      
      -- MERGE (INSERTなし)
      MERGE INTO テーブル1 T
      USING テーブル2 S ON (T.結合キー = S.結合キー)
      WHEN MATCHED AND T.条件 THEN
          UPDATE SET T.列A = S.列X;
                              

データ削除 (DELETE)

  • 特定の行を削除: `WHERE`句で対象行を指定します。指定しないと全行が削除されます。
    
    DELETE FROM テーブル名 WHERE 条件;
                    
  • 全行削除 (DELETE vs TRUNCATE):
    • `DELETE FROM テーブル名;`: トランザクションログに記録され、ロールバック可能。WHERE句がないだけで、行ごとに削除処理が走る。低速な場合がある。
    • `TRUNCATE TABLE テーブル名;`: トランザクションログ記録が最小限(または記録されない)。ロールバック不可な場合が多い。高速だが注意が必要。テーブル構造は残る。Auto Incrementもリセットされることが多い。
    
    -- 全行削除 (ロールバック可能)
    DELETE FROM テーブル名;
    
    -- 全行高速削除 (ロールバック不可の場合が多い、注意!)
    TRUNCATE TABLE テーブル名;
                    
  • 他のテーブルの条件に基づいて削除 (データベースによる違いあり):
    • 標準SQL / PostgreSQL / SQL Server: `USING`句や副問い合わせ、`JOIN`を使用
      
      -- SQL Server (JOIN)
      DELETE t1
      FROM テーブル1 t1
      INNER JOIN テーブル2 t2 ON t1.結合キー = t2.結合キー
      WHERE t2.条件;
      
      -- PostgreSQL (USING)
      DELETE FROM テーブル1 t1
      USING テーブル2 t2
      WHERE t1.結合キー = t2.結合キー AND t2.条件;
      
      -- 副問い合わせ (多くのDBで動作)
      DELETE FROM テーブル1
      WHERE 結合キー IN (SELECT 結合キー FROM テーブル2 WHERE 条件);
                              
    • MySQL: `JOIN`を使用
      
      DELETE t1
      FROM テーブル1 t1
      INNER JOIN テーブル2 t2 ON t1.結合キー = t2.結合キー
      WHERE t2.条件;
                              
    • Oracle: 副問い合わせを使用
      
      DELETE FROM テーブル1
      WHERE 結合キー IN (SELECT 結合キー FROM テーブル2 WHERE 条件);
                              

データ定義 (DDL – Data Definition Language)

データベースオブジェクト(テーブル、インデックスなど)を作成、変更、削除します。

テーブル操作 (TABLE)

  • テーブル作成 (CREATE TABLE): 列名、データ型、制約を指定します。
    
    CREATE TABLE 従業員 (
        従業員ID INT PRIMARY KEY, -- 主キー制約
        名前 VARCHAR(100) NOT NULL, -- NOT NULL制約
        部署ID INT,
        給与 DECIMAL(10, 2) CHECK (給与 >= 0), -- CHECK制約
        メールアドレス VARCHAR(255) UNIQUE, -- UNIQUE制約
        入社日 DATE DEFAULT CURRENT_DATE, -- デフォルト値
        FOREIGN KEY (部署ID) REFERENCES 部署(部署ID) -- 外部キー制約
    );
    
    -- AUTO_INCREMENT / IDENTITY / SERIAL (データベース依存)
    -- MySQL
    CREATE TABLE 商品 ( 商品ID INT AUTO_INCREMENT PRIMARY KEY, 商品名 VARCHAR(50) );
    -- SQL Server
    CREATE TABLE 商品 ( 商品ID INT IDENTITY(1,1) PRIMARY KEY, 商品名 VARCHAR(50) );
    -- PostgreSQL
    CREATE TABLE 商品 ( 商品ID SERIAL PRIMARY KEY, 商品名 VARCHAR(50) );
    -- Oracle (12c以降)
    CREATE TABLE 商品 ( 商品ID INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, 商品名 VARCHAR2(50) );
                    

    主なデータ型:

    分類 主な型 (例) 説明
    数値 `INT`, `INTEGER`, `SMALLINT`, `BIGINT`, `DECIMAL(p,s)`, `NUMERIC(p,s)`, `FLOAT`, `REAL`, `DOUBLE PRECISION` 整数、固定小数点数、浮動小数点数
    文字列 `CHAR(n)`, `VARCHAR(n)`, `TEXT`, `NCHAR(n)`, `NVARCHAR(n)` (Unicode) 固定長文字列、可変長文字列、長いテキスト
    日付/時刻 `DATE`, `TIME`, `TIMESTAMP`, `DATETIME` (DBによる) 日付、時刻、日付と時刻
    真偽値 `BOOLEAN`, `BOOL`, `BIT` (DBによる) 真 (True) または偽 (False)
    バイナリ `BINARY(n)`, `VARBINARY(n)`, `BLOB` バイナリデータ (画像など)

    注意: データ型の名称や機能はデータベース製品によって異なります。

  • テーブル変更 (ALTER TABLE): 列の追加、削除、変更、制約の追加、削除などを行います。
    
    -- 列の追加
    ALTER TABLE 従業員 ADD COLUMN 電話番号 VARCHAR(20);
    
    -- 列の削除
    ALTER TABLE 従業員 DROP COLUMN 入社日;
    
    -- 列のデータ型変更 (DBにより構文差異あり)
    -- PostgreSQL / SQL Server
    ALTER TABLE 従業員 ALTER COLUMN 名前 TYPE VARCHAR(150);
    -- MySQL
    ALTER TABLE 従業員 MODIFY COLUMN 名前 VARCHAR(150);
    -- Oracle
    ALTER TABLE 従業員 MODIFY (名前 VARCHAR2(150));
    
    -- 列名の変更 (DBにより構文差異あり)
    -- PostgreSQL / Oracle
    ALTER TABLE 従業員 RENAME COLUMN 電話番号 TO 連絡先;
    -- MySQL
    ALTER TABLE 従業員 CHANGE COLUMN 電話番号 連絡先 VARCHAR(20);
    -- SQL Server
    EXEC sp_rename '従業員.電話番号', '連絡先', 'COLUMN';
    
    -- 制約の追加
    ALTER TABLE 従業員 ADD CONSTRAINT chk_給与 CHECK (給与 > 0);
    ALTER TABLE 従業員 ADD FOREIGN KEY (部署ID) REFERENCES 部署(部署ID);
    
    -- 制約の削除 (制約名が必要な場合が多い)
    ALTER TABLE 従業員 DROP CONSTRAINT chk_給与;
    ALTER TABLE 従業員 DROP CONSTRAINT 従業員_部署ID_fkey; -- 制約名はDBや定義により異なる
                    
  • テーブル削除 (DROP TABLE): テーブルとそのデータ、インデックス、制約などを完全に削除します。
    
    DROP TABLE 従業員;
    
    -- 存在する場合のみ削除 (多くのDBでサポート)
    DROP TABLE IF EXISTS 従業員;
                    

インデックス操作 (INDEX)

検索パフォーマンスを向上させるために使用します。

  • インデックス作成 (CREATE INDEX):
    
    -- 通常のインデックス
    CREATE INDEX idx_従業員_名前 ON 従業員 (名前);
    
    -- 複合インデックス
    CREATE INDEX idx_従業員_部署_給与 ON 従業員 (部署ID, 給与 DESC);
    
    -- ユニークインデックス (一意制約と似ているが、NULLの扱いに差異がある場合あり)
    CREATE UNIQUE INDEX uidx_従業員_メール ON 従業員 (メールアドレス);
                    
  • インデックス削除 (DROP INDEX):
    
    -- MySQL / Oracle / SQL Server
    DROP INDEX idx_従業員_名前 ON 従業員;
    
    -- PostgreSQL
    DROP INDEX idx_従業員_名前;
                    

    注意: `DROP INDEX` の構文はデータベースによって異なります。

ビュー操作 (VIEW)

一つ以上のテーブルから導出される仮想的なテーブルです。クエリを単純化したり、セキュリティを向上させるために使用します。

  • ビュー作成 (CREATE VIEW):
    
    CREATE VIEW 東京顧客 AS
    SELECT 顧客ID, 名前, メールアドレス
    FROM 顧客
    WHERE 地域 = '東京';
    
    -- ビューを利用したクエリ
    SELECT * FROM 東京顧客 WHERE 名前 LIKE '田中%';
                    
  • ビュー変更 (ALTER VIEW or CREATE OR REPLACE VIEW):
    
    -- SQL Server / PostgreSQLなど
    ALTER VIEW 東京顧客 AS
    SELECT 顧客ID, 名前, メールアドレス, 電話番号 -- 列を追加
    FROM 顧客
    WHERE 地域 = '東京';
    
    -- Oracle / MySQL / PostgreSQLなど
    CREATE OR REPLACE VIEW 東京顧客 AS
    SELECT 顧客ID, 名前, メールアドレス, 電話番号
    FROM 顧客
    WHERE 地域 = '東京';
                    
  • ビュー削除 (DROP VIEW):
    
    DROP VIEW 東京顧客;
    
    -- 存在する場合のみ削除
    DROP VIEW IF EXISTS 東京顧客;
                    

データベース/スキーマ操作 (DATABASE / SCHEMA)

データベースやスキーマ(データベース内の名前空間)を管理します。

  • データベース作成 (CREATE DATABASE): (DBA権限が必要なことが多い)
    
    CREATE DATABASE 新しいデータベース名;
                    
  • スキーマ作成 (CREATE SCHEMA): (PostgreSQL, SQL Serverなどで使用)
    
    CREATE SCHEMA 販売管理スキーマ;
    -- スキーマを指定してテーブル作成
    CREATE TABLE 販売管理スキーマ.商品 ( ... );
                    
  • データベース/スキーマ削除 (DROP DATABASE / DROP SCHEMA): (非常に危険な操作!中のオブジェクトも全て削除される)
    
    DROP DATABASE データベース名;
    DROP SCHEMA スキーマ名; -- CASCADEオプションが必要な場合あり (中のオブジェクトも削除)
    DROP SCHEMA IF EXISTS スキーマ名 CASCADE;
                    

データ制御 (DCL – Data Control Language)

ユーザーのアクセス権限を管理します。

権限付与 (GRANT)

ユーザーまたはロールに対して、データベースオブジェクトへの操作権限を与えます。

  • 特定の操作権限を付与:
    
    -- user1 に '商品' テーブルへの SELECT 権限を付与
    GRANT SELECT ON 商品 TO user1;
    
    -- user2 に '顧客' テーブルへの SELECT, INSERT, UPDATE 権限を付与
    GRANT SELECT, INSERT, UPDATE ON 顧客 TO user2;
    
    -- public (全ユーザー) に '公開情報' ビューへの SELECT 権限を付与
    GRANT SELECT ON 公開情報 TO PUBLIC;
    
    -- sales_role ロールに '注文' テーブルへの全権限を付与
    GRANT ALL PRIVILEGES ON 注文 TO sales_role;
                    
  • 権限付与オプション (GRANT OPTION): 他のユーザーに権限を付与する権限も与えます。
    
    GRANT SELECT ON 顧客 TO manager_user WITH GRANT OPTION;
                     
  • ロールへの権限付与:
    
    -- ロールの作成 (DBによる)
    CREATE ROLE sales_staff;
    -- ロールに権限を付与
    GRANT SELECT, INSERT ON 注文 TO sales_staff;
    -- ユーザーにロールを付与
    GRANT sales_staff TO user3;
                     

権限剥奪 (REVOKE)

ユーザーまたはロールから権限を取り消します。

  • 特定の操作権限を剥奪:
    
    -- user1 から '商品' テーブルへの SELECT 権限を剥奪
    REVOKE SELECT ON 商品 FROM user1;
    
    -- user2 から '顧客' テーブルへの UPDATE 権限を剥奪
    REVOKE UPDATE ON 顧客 FROM user2;
    
    -- sales_role から '注文' テーブルへの DELETE 権限を剥奪
    REVOKE DELETE ON 注文 FROM sales_role;
                    
  • 権限付与オプション (GRANT OPTION) の剥奪: (DBにより `GRANT OPTION FOR` または `CASCADE` などの指定が異なる)
    
    -- 例: SQL Server / PostgreSQL
    REVOKE GRANT OPTION FOR SELECT ON 顧客 FROM manager_user;
    -- 例: Oracle (CASCADEで付与した権限も連鎖的に剥奪)
    REVOKE SELECT ON 顧客 FROM manager_user CASCADE;
                    

一連の DML 操作を一つの処理単位(トランザクション)として管理します。

トランザクションは、原子性(Atomicity)、一貫性(Consistency)、独立性(Isolation)、永続性(Durability)という ACID 特性を保証するための仕組みです。

トランザクションの開始

多くのデータベースでは、最初の DML 文 (INSERT, UPDATE, DELETE) が実行された時点で暗黙的にトランザクションが開始されます (自動コミットが無効な場合)。明示的に開始することも可能です。


-- 標準SQL / PostgreSQL / SQL Server など
BEGIN TRANSACTION;
-- または
BEGIN WORK;

-- MySQL
START TRANSACTION;
                

注意: 自動コミット(Auto Commit)設定が有効な場合、各 DML 文が即座にコミットされるため、明示的なトランザクション制御が必要です。

変更の確定 (COMMIT)

トランザクション内の全ての変更を確定し、データベースに永続的に反映させます。


COMMIT;
-- または
COMMIT WORK;
                

変更の取り消し (ROLLBACK)

トランザクション内の全ての変更を取り消し、トランザクション開始前の状態に戻します。


ROLLBACK;
-- または
ROLLBACK WORK;
                

セーブポイント (SAVEPOINT)

トランザクション内に中間ポイントを設定し、そこまでロールバックできるようにします。

  • セーブポイントの設定:
    
    SAVEPOINT ポイント名;
                    
  • セーブポイントまでロールバック:
    
    ROLLBACK TO SAVEPOINT ポイント名;
                    
  • セーブポイントの解放 (任意、COMMIT/ROLLBACKで自動解放されることが多い):
    
    -- Oracle
    RELEASE SAVEPOINT ポイント名;
    -- PostgreSQL (標準 SQL 準拠、ただし通常不要)
    RELEASE SAVEPOINT ポイント名;
                    

    注意: `RELEASE SAVEPOINT` はサポートされていない、または不要なデータベースもあります。

使用例:


BEGIN TRANSACTION;

INSERT INTO テーブルA VALUES (1);
SAVEPOINT sp1;

UPDATE テーブルB SET1 = 'X' WHERE ID = 10;
SAVEPOINT sp2;

INSERT INTO テーブルC VALUES (100);

-- 何か問題が発生したので、テーブルCへのINSERTを取り消したい
ROLLBACK TO SAVEPOINT sp2; -- テーブルCへのINSERTが取り消される

-- さらに問題があったので、テーブルBのUPDATEも取り消したい
ROLLBACK TO SAVEPOINT sp1; -- テーブルBのUPDATEも取り消される

-- 最終的に問題なければコミット (この例では最初のINSERTのみが残る)
-- COMMIT;
-- 全てを取り消す場合
-- ROLLBACK;
                

その他の便利な機能・関数

SQL をより強力にする様々な機能

条件分岐 (CASE 式)

条件に応じて返す値を切り替えます。

  • 単純 CASE 式: 列の値が特定の値と一致するかで分岐
    
    SELECT
      商品名,
      価格帯 = CASE サイズ
                WHEN 'S' THEN '小'
                WHEN 'M' THEN '中'
                WHEN 'L' THEN '大'
                ELSE 'その他'
               END
    FROM 商品;
                    
  • 検索 CASE 式: より複雑な条件で分岐
    
    SELECT
      商品名,
      価格カテゴリ = CASE
                      WHEN 価格 < 1000 THEN '低価格'
                      WHEN 価格 >= 1000 AND 価格 < 5000 THEN '中価格'
                      WHEN 価格 >= 5000 THEN '高価格'
                      ELSE '価格不明' -- NULL の場合など
                     END
    FROM 商品;
                    
  • UPDATE 文での利用:
    
    UPDATE 従業員
    SET 給与 = CASE 役職
                WHEN '部長' THEN 給与 * 1.1
                WHEN '課長' THEN 給与 * 1.05
                ELSE 給与
              END
    WHERE 評価 = 'A';
                    

NULL 値の処理関数

  • COALESCE(値1, 値2, …): 引数の中で最初に NULL でない値を返します。全て NULL なら NULL を返します。
    
    -- 電話番号が NULL なら '未登録' を表示
    SELECT 名前, COALESCE(電話番号, '未登録') AS 表示用電話番号 FROM 顧客;
                    
  • NULLIF(値1, 値2): 値1 と 値2 が等しい場合は NULL を返し、等しくない場合は 値1 を返します。ゼロ除算を防ぐのに使われることがあります。
    
    -- 数量が 0 の場合に NULL にして平均計算から除外する (例)
    SELECT AVG(価格 / NULLIF(数量, 0)) FROM 売上明細;
                    
  • ISNULL(値, 置換値) (SQL Server): 値が NULL なら置換値を返します。
    
    SELECT 名前, ISNULL(メールアドレス, 'N/A') FROM 従業員;
                    
  • IFNULL(値, 置換値) (MySQL): 値が NULL なら置換値を返します。`COALESCE`と似ていますが、引数は2つです。
    
    SELECT 商品名, IFNULL(割引率, 0) FROM 商品;
                    
  • NVL(値, 置換値) (Oracle): 値が NULL なら置換値を返します。`COALESCE`と似ていますが、引数は2つです。
    
    SELECT 従業員名, NVL(ボーナス, 0) FROM 給与;
                    

文字列操作関数

データベース製品によって関数名や挙動が異なる場合が多いです。

機能 関数例 (標準/代表的) 説明
連結 `||` (標準/PostgreSQL/Oracle), `CONCAT()` (標準/MySQL/PostgreSQL/SQL Server 2012+), `+` (SQL Server) 文字列を結合する (`SELECT ‘A’ || ‘B’;` or `SELECT CONCAT(‘A’, ‘B’);`)
長さ `LENGTH()`, `LEN()` (SQL Server), `CHAR_LENGTH()` 文字列の長さを返す (`SELECT LENGTH(‘abc’);`)
部分文字列 `SUBSTRING(str FROM start FOR len)`, `SUBSTR(str, start, len)` 文字列の一部を抽出する (`SELECT SUBSTRING(‘abcdef’ FROM 2 FOR 3); — ‘bcd’`)
置換 `REPLACE(str, from_str, to_str)` 文字列中の特定の部分を置換する (`SELECT REPLACE(‘abc abc’, ‘b’, ‘X’); — ‘aXc aXc’`)
大文字/小文字変換 `UPPER()`, `LOWER()` 文字列を大文字または小文字に変換する (`SELECT UPPER(‘abc’), LOWER(‘XYZ’);`)
トリム `TRIM()`, `LTRIM()`, `RTRIM()` 文字列の前後の空白(または指定文字)を除去する (`SELECT TRIM(‘ abc ‘); — ‘abc’`)
位置検索 `POSITION(substr IN str)`, `INSTR(str, substr)`, `CHARINDEX(substr, str)` (SQL Server) 文字列内で部分文字列が最初に出現する位置を返す (`SELECT POSITION(‘b’ IN ‘abc’); — 2`)

日付/時刻操作関数

データベース製品によって関数名や構文が大きく異なります。

機能 関数例 (代表的) 説明
現在日時取得 `CURRENT_TIMESTAMP`, `NOW()`, `GETDATE()` (SQL Server), `SYSDATE` (Oracle) 現在のサーバーの日付と時刻を取得する
現在日付取得 `CURRENT_DATE`, `CURDATE()` (MySQL) 現在の日付を取得する
日付/時刻要素抽出 `EXTRACT(unit FROM date)`, `DATE_PART(unit, date)` (PostgreSQL), `YEAR()`, `MONTH()`, `DAY()` (MySQL, SQL Server) 日付/時刻から年、月、日、時、分などを抽出する (`SELECT EXTRACT(YEAR FROM CURRENT_DATE);`)
日付/時刻加減算 `date + INTERVAL ‘n unit’`, `DATE_ADD(date, INTERVAL n unit)`, `DATEADD(unit, n, date)` (SQL Server) 日付/時刻に期間を加算/減算する (`SELECT CURRENT_DATE + INTERVAL ‘1’ MONTH;`)
日付/時刻差分計算 `date1 – date2`, `DATEDIFF(unit, date1, date2)` (SQL Server, MySQL), `AGE(date1, date2)` (PostgreSQL) 二つの日付/時刻の差を計算する
書式設定 `TO_CHAR(date, format)` (Oracle, PostgreSQL), `FORMAT(date, format)` (SQL Server 2012+), `DATE_FORMAT(date, format)` (MySQL) 日付/時刻を指定した書式に変換する (`SELECT TO_CHAR(NOW(), ‘YYYY/MM/DD HH24:MI:SS’);`)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です