AP データベース SQL基礎2

提供:yonewiki

AP データベースへ戻る。

AP データベース SQL基礎へ戻る。


応用情報処理技術者試験の出題範囲のSQL技術についてまとめている2ページ目の記事です。いきなりここに来てしまった人は上部リンクから戻れます。


社員
社員ID 氏名 所属部署 給与
1 山田太郎 営業部 300000
2 佐藤花子 開発部 400000
3 鈴木一郎 営業部 350000
4 田中美咲 総務部 280000

 


ALTER TABLE

 表に対する様々な変更をする句です。ALTER TABLEに続けて使うキーワードで、

  • 1.列の追加 (ADD COLUMN):
既存のテーブルに新しい列を追加します。
  • 2.列の削除 (DROP COLUMN):
既存のテーブルから列を削除します。
  • 3.列の変更 (ALTER COLUMN / MODIFY COLUMN):
既存の列のデータ型、NULL許容性、デフォルト値などを変更します。構文はデータベースシステムによって異なる場合があります(例: SQL Server, PostgreSQLはALTER COLUMN、MySQLはMODIFY COLUMN)。
  • 4.列名の変更 (RENAME COLUMN):
既存の列の名前を変更します。これもデータベースシステムによって構文が異なります (例: RENAME COLUMN old_name TO new_nameやCHANGE old_name new_name data_type)。
  • 5.制約の追加・削除 (ADD CONSTRAINT / DROP CONSTRAINT):
主キー、外部キー、UNIQUE、CHECKなどの制約を追加または削除します。
  • 6.テーブル名の変更 (RENAME TO):
テーブル自身の名前を変更します。


  • 1.列の追加


sql
ALTER TABLE 社員
ADD COLUMN 入社日 DATE;
sql


社員(入社日列追加後)
社員ID 氏名 所属部署 給与 入社日
1 山田太郎 営業部 300000 NULL
2 佐藤花子 開発部 400000 NULL
3 鈴木一郎 営業部 350000 NULL
4 田中美咲 総務部 280000 NULL


 このように列が追加されます。次は列を削除してもとに戻します。


2.列の変更

sql
ALTER TABLE 社員
MODIFY COLUMN 給与 BIGINT NOT NULL;
sql


上記で、社員テーブルの給与列にBIGINT型を設定して、NOT NULL制約を指定できます。


  • 3.列の削除


sql
ALTER TABLE 社員
DROP COLUMN 入社日;
sql


社員
社員ID 氏名 所属部署 給与
1 山田太郎 営業部 300000
2 佐藤花子 開発部 400000
3 鈴木一郎 営業部 350000
4 田中美咲 総務部 280000


4.制約の追加


sql
ALTER TABLE 社員
ADD CONSTRAINT PK_社員ID PRIMARY KEY (社員ID);
sql


 上記のようにすると社員テーブルの社員ID列を主キー設定にし、一意な値を保持し、NOT NULL制約を適用できます。


外部キー制約の追加

外部キー制約を追加する場合は以下のようになります。


sql
ALTER TABLE 社員
ADD CONSTRAINT FK_社員_部署 
FOREIGN KEY (所属部署)
REFERENCES 部署テーブル (部署名);
sql


外部キーを設定する列をFOREIGN KEY (所属部署)のように列指定し、外部キーとして参照するテーブルと列を、REFERENCES 部署テーブル (部署名)で指定するという記述方法になります。


5.制約の削除


sql
ALTER TABLE 社員
DROP CONSTRAINT PK_社員ID;
sql


 上記のようにすると社員テーブルの社員IDの制約を削除することができます。


6.テーブル名の変更


sql
ALTER TABLE 社員
RENAME TO 従業員;
sql


 上記のようにすると社員テーブルを従業員テーブルという名前に変更できます。


ON DELETE CASCADE・ON UPDATE CASCADE

 外部キーの削除変更があれば連動して、更新されたり、削除されたりする仕組みを形成します。


sql
ALTER TABLE 社員
ADD CONSTRAINT FK_社員_部署 FOREIGN KEY (所属部署)
REFERENCES 部署テーブル (部署名)
ON DELETE CASCADE
ON UPDATE CASCADE;
sql


このように連動定義をしていると


sql
DELETE FROM 部署テーブル
WHERE 部署名 = '総務部';
sql


のようにして総務部を削除すると、部署テーブルは


部署テーブル(総務部削除後)
部署名 拠点
営業部 東京
開発部 大阪
試作部 三重


となり


社員テーブル(総務部削除後の連動削除)
社員ID 氏名 所属部署 給与
1 山田太郎 営業部 300000
2 佐藤花子 開発部 400000
3 鈴木一郎 営業部 350000


 社員テーブルはこのように自動的に総務部の情報がなくなります。


 また営業部の名称を営業部から営業戦略部のように変更する以下のSQLを実行すると


sql
UPDATE 部署テーブル
SET 部署名 = '営業戦略部'
WHERE 部署名 = '営業部';
sql


部署テーブルは以下のようになり


部署テーブル(営業部更新後)
部署名 拠点
営業戦略部 東京
開発部 大阪
試作部 三重


 となり、社員テーブルは


社員テーブル(営業部更新後の連動更新)
社員ID 氏名 所属部署 給与
1 山田太郎 営業戦略部 300000
2 佐藤花子 開発部 400000
3 鈴木一郎 営業戦略部 350000


 のように連動して値が変更されます。便利ですが、本当に置き換えてしまうことで解決する関係であるかどうかまで熟知して利用する必要があります。

 

CREATE USER

 SQLシステムにログインして表を扱うユーザを追加する操作です。


sql
CREATE USER report_user WITH PASSWORD 'password123';
CREATE USER app_user WITH PASSWORD 'password456';
sql


 これでレポートを出力するためのユーザreport_user(任意のユーザ名)とアプリを動かすときにアプリがSQL問合せをするときの権限のユーザapp_userをそれぞれパスワードを指定して作成したことになります。

 

REVOKE

 権限をなくすための句です。

sql
REVOKE ALL PRIVILEGES ON TABLE 社員 FROM report_user;
REVOKE ALL PRIVILEGES ON TABLE 部署テーブル FROM report_user;
REVOKE ALL PRIVILEGES ON TABLE 社員 FROM app_user;
REVOKE ALL PRIVILEGES ON TABLE 部署テーブル FROM app_user;
sql


 すべての権限を各テーブルからはく奪するには上記のようなSQLを使います。

 

GRANT

 ユーザの権限と表の権限の関係を設定するものです。


sql
GRANT SELECT ON TABLE 社員 TO report_user;
GRANT SELECT ON TABLE 部署テーブル TO report_user;
sql


 部署テーブルと社員テーブルにselectのような射影操作だけをreport_userに許可する権限設定となりました。


 これでreport_userは以下のようなSQLが実行できます。


sql
SELECT * FROM 社員;
SELECT 部署名, 拠点 FROM 部署テーブル WHERE 部署名 = '営業部';
sql


 ただし、以下のようなSQLは実行できません。


sql
INSERT INTO 社員 (社員ID, 氏名, 所属部署, 給与) VALUES (5, '新入社員', '開発部', 300000);
DELETE FROM 社員 WHERE 社員ID = 1;
UPDATE 社員 SET 給与 = 500000 WHERE 社員ID = 1;
sql


 app_userには、より様々なことができる権限を設定するとしたら、以下のようなSQLを実行します。


sql
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE 社員 TO app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE 部署テーブル TO app_user;
sql


 上記によりapp_userはSELECT、INSERT、UPDATE、DELETEを実行できる。


 社員テーブルの氏名、所属部署列のみ更新できる権限をapp_userに設定する場合は以下のとおりのSQLとなる。


sql
GRANT UPDATE (氏名, 所属部署) ON TABLE 社員 TO app_user;
sql


 あらゆる権限を付与する場合には以下のようなALL PRIVILEGES句を使ったSQLを実行します。


sql
GRANT ALL PRIVILEGES ON TABLE 社員 TO app_user;
GRANT ALL PRIVILEGES ON TABLE 部署テーブル TO app_user;
sql


 このようなGRANTによる権限設定のみをできるようにするには


sql
GRANT ALL PRIVILEGES ON TABLE 社員 TO report_user WITH GRANT OPTION;
sql


 のようにWITH GRANT OPTIONという句をつけます。

 

CASE

 表の中で表示する値をIF文を使って、条件に応じた値を表示するのに使います。


sql
SELECT
    氏名,
    給与,
    CASE
        WHEN 給与 >= 350000 THEN '高給与'
        WHEN 給与 >= 300000 THEN '中給与'
        ELSE '低給与'
    END AS 給与ランク
FROM
    社員
ORDER BY
    給与 DESC;
sql


 上記の例では、新たに給与ランクという列を表示用のために新たに作り(表自体に列を追加するわけではない)、既存の列、給与の列の値によって、表示する値を決めています。給与が35万円以上なら高給与、それ以外の値の中で30万以上なら中給与、それ以外なら低給与と表示します。


 結果として以下のような表の出力を得ます。


社員の給与ランク
氏名 給与 給与ランク
佐藤花子 400000 高給与
鈴木一郎 350000 高給与
山田太郎 300000 中給与
田中美咲 280000 低給与


 SELECT句の列の指定のところで、CASE WHEN 条件 THEN 表示値 ELSE 表示値 END AS 列名のような指定をします。列指定に複雑なキーワードを設定していると思えば良いです。

 

ウィンドウ関数

 列の表示に関数を指定することで、GROUP BY で設定した範囲で集計したり OVER (PARTITION BY)句で設定したグループごとで集計したりすることができます。この時、列の指定値として記述する関数をウィンドウ関数と呼んでいます。さまざまなウィンドウ関数サンプルを示すために、これまでの社員テーブルを以下のように拡張したものとして説明したいと思います。


拡張された社員テーブル
社員ID 氏名 所属部署 給与 入社年度 評価点
1 山田太郎 営業部 300000 2020 85
2 佐藤花子 開発部 400000 2018 92
3 鈴木一郎 営業部 350000 2019 88
4 田中美咲 総務部 280000 2021 78
5 高橋健太 開発部 420000 2019 95
6 伊藤美穂 営業部 300000 2020 80
7 小林大輔 開発部 380000 2020 90

 

AVG、SUM、OVER句を使った例

 平均や合計を算出するウィンドウ関数です。集計グループはOVER句の中にPARTITION BY句を使って示すことで各行に全体やある列の何かの値ごとグループ化された値について関数で集計した結果を各行に示すことができます。


sql
SELECT
    氏名,
    所属部署,
    給与,
    AVG(給与) OVER (PARTITION BY 所属部署) AS 部署平均給与,
    SUM(給与) OVER (PARTITION BY 所属部署) AS 部署給与総額,
    AVG(給与) OVER () AS 全体平均給与, -- PARTITION BY なしは全体に対して
    SUM(給与) OVER () AS 全体給与総額   -- PARTITION BY なしは全体に対して
FROM
    社員
ORDER BY
    所属部署, 給与 DESC;
sql


 上記のようなSQLを実行すると、以下のような表を得ることができます。


社員と集計ウィンドウ関数の結果
氏名 所属部署 給与 部署平均給与 部署給与総額 全体平均給与 全体給与総額
高橋健太 開発部 420000 400000.00 1200000 352857.14 2470000
佐藤花子 開発部 400000 400000.00 1200000 352857.14 2470000
小林大輔 開発部 380000 400000.00 1200000 352857.14 2470000
鈴木一郎 営業部 350000 316666.67 950000 352857.14 2470000
山田太郎 営業部 300000 316666.67 950000 352857.14 2470000
伊藤美穂 営業部 300000 316666.67 950000 352857.14 2470000
田中美咲 総務部 280000 280000.00 280000 352857.14 2470000

 

AVG、SUM、OVER句を使わない例

 OVER句を使わない場合は、1行にまとまった結果を得ることができます。


sql
SELECT
    SUM(給与) AS 全体給与総額,
    AVG(給与) AS 全体平均給与,
    COUNT(社員ID) AS 総社員数
FROM
    社員;
sql


会社全体の集計結果
全体給与総額 全体平均給与 総社員数
2470000 352857.14 7


 OVER句を使わない場合はこのような集計表示になります。1行に集約しようとします。したがって、ある列ではOVER句をつかっているのにある列ではOVER句の指定がない場合には1行に集約しようとしているのに、一行に集約しないものを使おうとしているということで矛盾が生じ、SQLの実行はエラーになります。

 

ROW_NUMBER, RANK, DENSE_RANK

  • ROW_NUMBER:順序内の位置に応じて一意の連番を付与します。
  • RANK:同じ値を持つ行には同じ順位を付与し、次の順位は同順位の数だけスキップされます。スポーツ競技の順位付けと同じ仕組みです。
  • DENSE_RANK:同じ値を持つ行には同じ順位を付与しますが、次の順位はスキップされずに連続します。すべての順位を使います。


sql
SELECT
    氏名,
    所属部署,
    給与,
    ROW_NUMBER() OVER (PARTITION BY 所属部署 ORDER BY 給与 DESC) AS 部署内順位_ROW_NUMBER,
    RANK() OVER (PARTITION BY 所属部署 ORDER BY 給与 DESC) AS 部署内順位_RANK,
    DENSE_RANK() OVER (PARTITION BY 所属部署 ORDER BY 給与 DESC) AS 部署内順位_DENSE_RANK
FROM
    社員
ORDER BY
    所属部署, 給与 DESC;
sql


社員の部署内順位
氏名 所属部署 給与 部署内順位_ROW_NUMBER 部署内順位_RANK 部署内順位_DENSE_RANK
高橋健太 開発部 420000 1 1 1
佐藤花子 開発部 400000 2 2 2
小林大輔 開発部 380000 3 3 3
鈴木一郎 営業部 350000 1 1 1
山田太郎 営業部 300000 2 2 2
伊藤美穂 営業部 300000 3 2 2
田中美咲 総務部 280000 1 1 1

 

LAG, LEAD

LAG:引数の1番目はn前の対象列名、引数の2番目はn前のn、引数の3番目は対象が無い場合の値を指定します。 LEAD:引数の1番目はn後の対象列名、引数の2番目はn後のn、引数の3番目は対象が無い場合の値を指定します。


sql
SELECT
    氏名,
    所属部署,
    給与,
    LAG(給与, 1, 0) OVER (PARTITION BY 所属部署 ORDER BY 入社年度) AS 前の社員の給与,
    LEAD(給与, 1, 0) OVER (PARTITION BY 所属部署 ORDER BY 入社年度) AS 次の社員の給与
FROM
    社員
ORDER BY
    所属部署, 入社年度;
sql


社員と前後給与
氏名 所属部署 給与 前の社員の給与 次の社員の給与
佐藤花子 開発部 400000 0 420000
高橋健太 開発部 420000 400000 380000
小林大輔 開発部 380000 420000 0
鈴木一郎 営業部 350000 0 300000
山田太郎 営業部 300000 350000 300000
伊藤美穂 営業部 300000 300000 0
田中美咲 総務部 280000 0 0

 

NTILE, MIN, MAX, COUNT

  • NTILE:ランキングを指定した数字のグループに分ける関数です。
  • MIN:最小値を返す関数です。
  • MAX:最大値を返す関数です。
  • COUNT:指定した列名の行数を返す関数です。単にレコード総数を得たい場合は列名の指定を省略した * でもよいです。ただし、列名を指定した場合はNULLであったレコードを省いてカウントしてくれますので、違いはあります。


sql
SELECT
    氏名,
    所属部署,
    給与,
    評価点,
    NTILE(3) OVER (ORDER BY 給与 DESC) AS 全体給与上位3グループ, -- 全体を3グループに分割
    MIN(給与) OVER (PARTITION BY 所属部署) AS 部署内最低給与,
    MAX(給与) OVER (PARTITION BY 所属部署) AS 部署内最高給与,
    COUNT(社員ID) OVER (PARTITION BY 所属部署) AS 部署社員数,
    COUNT(社員ID) OVER () AS 全体社員数
FROM
    社員
ORDER BY
    全体給与上位3グループ, 所属部署, 給与 DESC;
sql


社員と各種ウィンドウ関数の結果
氏名 所属部署 給与 評価点 全体給与上位3グループ 部署内最低給与 部署内最高給与 部署社員数 全体社員数
高橋健太 開発部 420000 95 1 380000 420000 3 7
佐藤花子 開発部 400000 92 1 380000 420000 3 7
鈴木一郎 営業部 350000 88 1 300000 350000 3 7
小林大輔 開発部 380000 90 2 380000 420000 3 7
山田太郎 営業部 300000 85 2 300000 350000 3 7
伊藤美穂 営業部 300000 80 3 300000 350000 3 7
田中美咲 総務部 280000 78 3 280000 280000 1 7

 

WINDOW

 ウィンドウ関数を使っていた時にグループ化していたOVER句の中のPARTITION句をまとめて書くような手法のためにあるものです。


sql
SELECT
    氏名,
    所属部署,
    給与,
    RANK() OVER w_dept_salary_desc AS 部署内給与ランク,
    MIN(給与) OVER w_dept AS 部署内最低給与,
    MAX(給与) OVER w_dept AS 部署内最高給与,
    COUNT(社員ID) OVER w_dept AS 部署社員数
FROM
    社員
WINDOW
    w_dept AS (PARTITION BY 所属部署), -- 部署ごとのウィンドウ定義
    w_dept_salary_desc AS (PARTITION BY 所属部署 ORDER BY 給与 DESC) -- 部署ごと、給与降順のウィンドウ定義
ORDER BY
    所属部署, 給与 DESC;
sql


WINDOW句を使った社員の分析
氏名 所属部署 給与 部署内給与ランク 部署内最低給与 部署内最高給与 部署社員数
高橋健太 開発部 420000 1 380000 420000 3
佐藤花子 開発部 400000 2 380000 420000 3
小林大輔 開発部 380000 3 380000 420000 3
鈴木一郎 営業部 350000 1 300000 350000 3
山田太郎 営業部 300000 2 300000 350000 3
伊藤美穂 営業部 300000 2 300000 350000 3
田中美咲 総務部 280000 1 280000 280000 1

 

COALESCE 関数

 表示結果がNULL値のときの代わりの値を指定できる関数です。


 以下のようなテーブルがあったとして


拡張された連絡先テーブル
社員ID 氏名 電話番号 メールアドレス 住所
1 山田太郎 090-1111-2222 yamada@example.com 東京都
2 佐藤花子 080-3333-4444 sato@example.com NULL
3 鈴木一郎 NULL suzuki@example.com 神奈川県
4 田中美咲 070-5555-6666 NULL NULL
5 高橋健太 NULL NULL 大阪府
6 伊藤美穂 NULL NULL NULL


sql
SELECT
    社員ID,
    氏名,
    電話番号,
    メールアドレス,
    住所,
    COALESCE(電話番号, メールアドレス, 住所, '不明') AS 主な連絡先
FROM
    連絡先;
sql


連絡先とCOALESCE関数の結果
社員ID 氏名 電話番号 メールアドレス 住所 主な連絡先
1 山田太郎 090-1111-2222 yamada@example.com 東京都 090-1111-2222
2 佐藤花子 080-3333-4444 sato@example.com NULL 080-3333-4444
3 鈴木一郎 NULL suzuki@example.com 神奈川県 suzuki@example.com
4 田中美咲 070-5555-6666 NULL NULL 070-5555-6666
5 高橋健太 NULL NULL 大阪府 大阪府
6 伊藤美穂 NULL NULL NULL 不明

 

SUBSTRING, INSTR, LENGTH, UPPER, LOWER

  • SUBSTRING:第一引数は抽出列名、第二引数は抽出開始文字位置、第三引数は抽出終了文字位置
  • INSTR:第一引数は検索列名、第二引数は検索文字で列名の中の値で検索された最初の文字位置を前方からの文字位置を返す
  • LENGTH:引数に列名を与えると列値の文字列の文字数を返す。
  • UPPER:引数に列名を与えると列値の中に含まれるアルファベット文字をすべて大文字に変換する。
  • LOWER:引数に列名を与えると列値の中に含まれるアルファベット文字をすべて大文字に変換する。


社員連絡先テーブル
社員ID 氏名 メールアドレス
1 山田太郎 yamada@example.com
2 佐藤花子 sato@example.com
3 鈴木一郎 suzuki@example.com
4 田中美咲 tanaka.misaki@example.com
5 高橋健太 takahashi@example.com


sql
WITH 初期データ AS (
    SELECT
        氏名,
        メールアドレス,
        -- ここで最初の計算を行い、エイリアスを設定
        SUBSTRING(メールアドレス, 1, INSTR(メールアドレス, '@') - 1) AS メールアドレス_ローカルパート,
        LENGTH(氏名) AS 氏名_文字数
    FROM
        社員連絡先
)
SELECT
    氏名,
    メールアドレス,
    メールアドレス_ローカルパート,
    氏名_文字数,
    -- CTEで作成した'メールアドレス_ローカルパート'をここで利用
    UPPER(メールアドレス_ローカルパート) AS メールアドレス_ローカルパート大文字,
    LOWER(メールアドレス) AS メールアドレス_小文字化
FROM
    初期データ;
sql


Common Table Expression(共通テーブル式)を作るWITH句を使って一度メールアドレス_ローカルパートを計算させると、その後のSELECT句でメールアドレス_ローカルパート列を使って大文字変換関数UPPERの引数にできます。


CTEを使った文字列操作関数の結果
氏名 メールアドレス メールアドレス_ローカルパート 氏名_文字数 メールアドレス_ローカルパート大文字 メールアドレス_小文字化
山田太郎 yamada@example.com yamada 4 YAMADA yamada@example.com
佐藤花子 sato@example.com sato 4 SATO sato@example.com
鈴木一郎 suzuki@example.com suzuki 4 SUZUKI suzuki@example.com
田中美咲 tanaka.misaki@example.com tanaka.misaki 4 TANAKA.MISAKI tanaka.misaki@example.com
高橋健太 takahashi@example.com takahashi 4 TAKAHASHI takahashi@example.com

 

文字列関数

CONCAT

  • CONCAT(str1, str2, ...): 文字列を結合。

 

TRIM, LTRIM, RTRIM

  • TRIM(str) / LTRIM(str) / RTRIM(str): 空白文字を削除(全体、左、右)。

 

REPLACE

  • REPLACE(str, from_str, to_str): 文字列内の特定のサブ文字列を置換。

 

LEFT, RIGHT

  • LEFT(str, len) / RIGHT(str, len): 文字列の左/右から指定文字数分抽出。

 

LPAD, RPAD

  • LPAD(str, len, pad_str) / RPAD(str, len, pad_str): 文字列を指定した長さまで埋める(左/右)。

 

数値関数

ROUND

  • ROUND(num, decimal_places): 数値を四捨五入。

 

FLOOR

  • FLOOR(num): 数値の小数点以下を切り捨て。

 

CEIL, CEILING

  • CEIL(num) / CEILING(num): 数値の小数点以下を切り上げ。

 

ABS

  • ABS(num): 数値の絶対値。

 

POWER

  • POWER(base, exponent): べき乗。

 

SQRT

  • SQRT(num): 平方根。

 

RAND, RANDOM

  • RAND() / RANDOM(): 乱数生成。

 

日付/時刻関数

NOW, CURRENT_TIMESTAMP

  • NOW() / CURRENT_TIMESTAMP: 現在の日付と時刻。

 

CURDATE, CURRENT_DATE

  • CURDATE() / CURRENT_DATE: 現在の日付。

 

YEAR, MONTH, DAY

  • YEAR(date) / MONTH(date) / DAY(date): 日付から年/月/日を抽出。

 

DATEDIFF, DATE_PART

  • DATEDIFF(unit, start_date, end_date) / DATE_PART('unit', date): 2つの日付間の差、または日付の一部を抽出。

 

DATE_ADD, DATE_SUB

  • DATE_ADD(date, INTERVAL value unit) / DATE_SUB(date, INTERVAL value unit): 日付に期間を加算/減算。

 

FORMAT

  • FORMAT(value, format): 値を指定した形式で整形(特に日付)。

 

変換関数

CAST, CONVERT

  • CAST(expression AS type) / CONVERT(type, expression): データ型を変換。

 

TO_CHAR, FORMAT

  • TO_CHAR(value, format) (Oracle/PostgreSQL) / FORMAT(value, format) (SQL Server): 値を特定の書式で文字列に変換。

 

TO_DATE

  • TO_DATE(string, format) (Oracle/PostgreSQL): 文字列を日付型に変換。

 

NULL関連関数

IFNULL, ISNULL

  • IFNULL(expr1, expr2) (MySQL) / ISNULL(expr1, expr2) (SQL Server): expr1がNULLならexpr2を返す。COALESCEの2引数版。

 

NULLIF

  • NULLIF(expr1, expr2): expr1とexpr2が同じならNULLを返し、そうでなければexpr1を返す。

 

CREATE INDEX

 社員数が10万人とかになってくるとインデックスというものを作るとインデックスを作った特定列の検索の速度が速くなります。例えば社員テーブルの所属部署列にインデックスを作るには以下のようにします。検索が速くなりますがインデックスを整備し続けるためデータの更新などがあった場合のインデックス再構成に時間がかかるため、更新が若干遅くなるのが普通です。


sql
CREATE INDEX idx_社員_所属部署
ON 社員 (所属部署);
sql


 メールアドレスのような、一意に決まる列でインデックスを作る場合は以下のように一意インデックスを作ることができます。


sql
CREATE UNIQUE INDEX uix_社員_メールアドレス
ON 社員 (メールアドレス);
sql


 所属部署と給与の組み合わせで検索やソートが頻繁に行われる場合、複合インデックスを作成することができ、以下のようにします。


sql
CREATE INDEX idx_社員_所属部署_給与
ON 社員 (所属部署, 給与 DESC); -- 所属部署で昇順、給与で降順にインデックスを張る
sql


具体例として以下のような効果が得られます。


インデックス作成前後のクエリ実行時間比較 (概念)
クエリ インデックス作成前 (時間) インデックス作成後 (時間) 備考
SELECT * FROM 社員 WHERE 所属部署 = '開発部'; 1000ms 10ms idx_社員_所属部署が利用
SELECT * FROM 社員 WHERE メールアドレス = 'foo@example.com'; 800ms 5ms uix_社員_メールアドレスが利用
SELECT * FROM 社員 ORDER BY 所属部署, 給与 DESC; 1200ms 20ms idx_社員_所属部署_給与が利用
INSERT INTO 社員 VALUES (...); 10ms 12ms インデックス更新のオーバーヘッド

 

AP データベース SQL基礎へ戻る。

AP データベースへ戻る。