目的別 SQL クイックリファレンス
データ検索 (SELECT)
テーブルから情報を取得するための基本的な操作です。
基本的な検索
- 全ての列を取得:
SELECT * FROM テーブル名;
- 特定の列を取得:
SELECT 列1, 列2 FROM テーブル名;
- 重複を除外して取得 (DISTINCT):
SELECT DISTINCT 列1 FROM テーブル名;
- 別名 (エイリアス) を使用:
SELECT 列1 AS 別名1, 列2 AS 別名2 FROM テーブル名; SELECT t.列1, t.列2 FROM テーブル名 AS t; -- テーブルにも別名
条件指定 (WHERE)
特定の条件に一致する行のみを取得します。
- 基本的な比較演算子: `=`, `<>` (または `!=`), `<`, `>`, `<=`, `>=`
SELECT 列1, 列2 FROM テーブル名 WHERE 列1 = '値'; SELECT 列1, 列2 FROM テーブル名 WHERE 列2 > 100;
- 論理演算子 (AND, OR, NOT):
SELECT * FROM テーブル名 WHERE 列1 = '値1' AND 列2 < 50; SELECT * FROM テーブル名 WHERE 列1 = '値1' OR 列1 = '値2'; SELECT * FROM テーブル名 WHERE NOT 列1 = '特定の値';
- 範囲指定 (BETWEEN):
SELECT * FROM テーブル名 WHERE 列1 BETWEEN 10 AND 20; -- 10と20を含む
- リスト指定 (IN):
SELECT * FROM テーブル名 WHERE 列1 IN ('値A', '値B', '値C');
- パターンマッチング (LIKE): `%` (任意の文字列), `_` (任意の1文字)
SELECT * FROM テーブル名 WHERE 列1 LIKE 'A%'; -- Aで始まる SELECT * FROM テーブル名 WHERE 列1 LIKE '%パターン%'; -- パターンを含む SELECT * FROM テーブル名 WHERE 列1 LIKE 'A_C'; -- Aで始まり、Cで終わる3文字
注意: エスケープ文字はデータベースによって異なる場合があります (例: `\`)
- NULL 値の判定 (IS NULL, IS NOT NULL):
SELECT * FROM テーブル名 WHERE 列1 IS NULL; SELECT * FROM テーブル名 WHERE 列1 IS NOT NULL;
結果の並び替え (ORDER BY)
取得した結果を指定した列で並び替えます。
- 昇順 (ASC – デフォルト):
SELECT * FROM テーブル名 ORDER BY 列1 ASC; SELECT * FROM テーブル名 ORDER BY 列1; -- ASCは省略可能
- 降順 (DESC):
SELECT * FROM テーブル名 ORDER BY 列1 DESC;
- 複数列での並び替え:
SELECT * FROM テーブル名 ORDER BY 列1 ASC, 列2 DESC;
- 列番号での指定 (非推奨だが可能):
SELECT 列1, 列2 FROM テーブル名 ORDER BY 1 DESC; -- 1番目の列(列1)で降順ソート
結果の制限 (LIMIT / TOP / ROWNUM)
取得する行数を制限します。構文はデータベース製品によって異なります。
データベース | 構文例 (先頭からN件) | 構文例 (M行目からN件) |
---|---|---|
MySQL, PostgreSQL, SQLite |
|
|
SQL Server |
|
|
Oracle |
|
|
集計関数とグループ化 (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) | 両方のテーブルに結合キーが存在する行のみを結合します。 |
|
LEFT JOIN (または LEFT OUTER JOIN) | 左側のテーブル(t1)の全ての行と、右側のテーブル(t2)で結合キーが一致する行を結合します。一致しない場合は右側の列はNULLになります。 |
|
RIGHT JOIN (または RIGHT OUTER JOIN) | 右側のテーブル(t2)の全ての行と、左側のテーブル(t1)で結合キーが一致する行を結合します。一致しない場合は左側の列はNULLになります。 |
|
FULL OUTER JOIN | 左右両方のテーブルの全ての行を結合します。どちらかのテーブルにしか存在しない場合は、存在しない側の列はNULLになります。(MySQLは標準ではサポートしていません) |
|
CROSS JOIN | 両方のテーブルの行の全ての組み合わせ(デカルト積)を生成します。結合条件は指定しません。 |
|
SELF JOIN | 同じテーブル同士を結合します。テーブルに別名をつける必要があります。 |
|
副問い合わせ (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 顧客地域 = '東京');
- 単一値を返す副問い合わせ: 比較演算子 (`=`, `>`, etc.) と共に使用します。
- 相関副問い合わせ (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) SELECT 値1A, 値2A UNION ALL SELECT 値1B, 値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 UPDATE 列1 = '新しい値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 SET 列1 = 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'); -- 存在すれば無視
- MySQL: `INSERT … ON DUPLICATE KEY UPDATE`
データ更新 (UPDATE)
- 特定の行を更新: `WHERE`句で対象行を指定します。指定しないと全行が更新されます。
UPDATE テーブル名 SET 列1 = 新しい値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;
- 標準SQL / PostgreSQL / SQL Server: `FROM`句や`JOIN`を使用
データ削除 (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 条件);
- 標準SQL / PostgreSQL / SQL Server: `USING`句や副問い合わせ、`JOIN`を使用
データ定義 (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;
トランザクション制御 (TCL – Transaction Control Language)
一連の 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 SET 列1 = '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’);`) |