本コーディング規約は、世の中のシステム開発プロジェクトのために無償で提供致します。
ただし、掲載内容および利用に際して発生した問題、それに伴う損害については、フューチャー株式会社は一切の責務を負わないものとします。
また、掲載している情報は予告なく変更することがございますので、あらかじめご了承下さい。
本書は、SQL コーディング規約についてまとめたものである。
今回 RDBMS として採用する Oracle での SQL
の使用を前提に記述している。
本章では可読性・管理性を高めることを目的としたコーディング規約について記載する。
書式全般についてのコーディング規約を下記に示す。
予約語に対しては、大文字を使用する。(例 :
SELECT
、INSERT
、UPDATE
、DELETE
等)
予約語以外に対しても、予約語と同様に大文字を使用する。(例 : オブジェクト名、カラム名 等)
SQL 中に記述するエイリアス名など単語の短縮について示す。
外来語に関しては、原語の短縮形を使用する。短縮形が存在しない場合には、母音を抜かして表記する。
例) corporation → corp / computer → cmptr
ローマ字の短縮は、単語の区切れの頭文字、または母音を抜かした子音字等を利用する。
例) nichijo → nchj
SQL ファイルの文字コード(エンコーディング)は Java ソースファイルと同じく『 Unicode UTF-8 』で保存する。
不要な空白文字(スペース)は除去すること。
DML 文の節に対する予約語は左揃えにする。
項目ごとに改行を入れ、項目の前にはインデントを挿入する。カンマは項目の前へ記入する。
Java ソースファイルのようにファイルの先頭にコメント行を入れると DB
分析作業に支障があるため禁止とする。
よって SQL
ファイルの先頭は必ずSELECT
、UPDATE
、INSERT
、DELETE
、MERGE
の何れかになる。
物理カラム名、テーブル名に対応する論理名を入れる場合、その後ろに単数行コメント(--
)にて記述する。
SQL
内に挿入する単数行コメントは、/*(半角スペース)コメント本文(半角スペース)*/
で行う。
,
(カンマ)とAND
については各行の先頭に記述する。(以下の例を参照のこと)
SQL フレームワークで実行する SQL の場合、SQL
ステートメントの終わりを示す;
(セミコロン)は記述しない。
良い例:
SELECT
/*
処理名
*/
AS COLUMN1 -- カラム1
TBL1.COLUMN1 AS COLUMN2 -- カラム2
, TBL1.COLUMN2 FROM
-- テーブル1 TABLE1 TBL1
WHERE
句の=
、!=
、IS
(IS NULL
のIS
)の縦位置は揃える。
良い例:
WHERE
= B.TEN_NO
A.TEN_NO AND A.KAMOKU_CD != '1'
AND A.ANKEN_NO IS NULL
良い例:
SELECT
AS COLUMN1 -- カラム1
TBL1.COLUMN1 AS COLUMN2 -- カラム2
, TBL1.COLUMN2 FROM
-- テーブル1
TABLE1 TBL1 WHERE
= 1
TBL1.COLUMN3 ORDER BY
TBL1.COLUMN1 , TBL1.COLUMN2
良い例:
INSERT
INTO
-- テーブル1
TABLE1
(-- カラム1
COLUMN1 -- カラム2
, COLUMN2 -- カラム3
, COLUMN3 VALUES (
)
VALUE1
, VALUE2
, VALUE3 )
良い例:
UPDATE
-- テーブル1
TABLE1 TBL1 SET
= 100 -- カラム2
TBL1.COLUMN2 = 100 -- カラム3
, TBL1.COLUMN3 WHERE
= 10 TBL1.COLUMN1
良い例:
DELETE
FROM
-- テーブル1
TABLE1 TBL1 WHERE
VALUE = 1 TBL1.
DB 結合条件が一致した場合と不一致になった場合の、それぞれの SQL 文を記述する。
良い例:
MERGE
INTO
PROFILE P -- PROFILEテーブル
USING
-- NAMEテーブル
NAME N ON
(= N.NAME -- 条件
P.NAME
)WHEN MATCHED THEN -- 条件が一致
/*UPDATE文*/
WHEN NOT MATCHED THEN -- 条件が不一致
/*INSERT文*/
良い例:
AND XXX = (
SELECT
TBL1.COLUMN1
, TBL1.COLUMN2FROM
TABLE1 TBL1 )
CASE 式は下記のように記載すること。
良い例:
CASE
WHEN
= YYY.FUGA
XXX.HOGE AND XXX.FUGA = YYY.FUGA
THEN
1
ELSE
0
END
CASE
、WHEN
、THEN
、ELSE
の後に改行を挿入すること。
CASE
の後、END
の前までは 1
インデント挿入すること。
カンマの後にスペースを1文字入れる。
比較演算子の前後にタブ(またはスペース)を1文字入れる。
SELECT 句、ORDER BY 句、GROUP BY
句等は最初に出現するカラムとカラムの区切りのカンマ前に改行を入れること。
SELECT の FROM
句の最初に出現するテーブルと結合テーブルの区切りのカンマ前に改行を入れること。
WHERE 句、MERGE の ON 句の各条件文の(AND や OR
の)前に改行を入れること。
命令句の後は、ヒント句が挿入できるように改行すること。
良い例:
SELECT
AS COLUMN1
T1.COLUMN1 AS COLUMN2
, T2.COLUMN2 FROM
TABLE1 T1
, TABLE2 T2WHERE
= 1
T1.COLUMN3 AND T1.COLUMN4 = T2.COLUMN4
ORDER BY
T1.COLUMN1 , T2.COLUMN2
WITH の前後に改行を挿入すること
また、インデントは下記のように記述すること
良い例:
-- カラムエイリアスあり
WITH
NAME1 (-- カラム1
COL_ALIAS1 -- カラム2
, COL_ALIAS2 AS (
) SELECT
・・・
)
, NAME2 (-- カラム1
COL_ALIAS1 -- カラム2
, COL_ALIAS2 AS (
) SELECT
・・・
)
-- カラムエイリアスなし
WITH
AS (
NAME1 SELECT
・・・
)AS (
, NAME2 SELECT
・・・ )
OFFSET、FETCH の前に改行を挿入すること
良い例:
SELECT
AS COLUMN1
TBL1.COLUMN1 FROM
TABLE1 TBL1ORDER BY
DESC
TBL1.COLUMN2 5 ROWS
OFFSET NEXT 5 ROWS ONLY FETCH
HINT 句は独立した行で記載すること
HINT 内容にはインデントを付けること
良い例:
SELECT
/*+
ここにHINTを記載
*/
AS COLUMN1
TBL1.COLUMN1 FROM
TABLE1 TBL1WHERE
= 1 TBL1.COLUMN2
修正コメント
(修正コメントが必要な場合、)
処理追加の際、追加行の 1
行目の前と最終行の次の行にコメントを入れる。単一行の場合は、同一行の最後にコメントをつける。
良い例:
-- 2004/04/23 仕様変更管理番号 ADD(または、MOD、DEL) 変更者名 S ← 修正開始点コメント
(追加処理)-- 2004/04/23仕様変更管理番号 ADD(または、MOD、DEL) 変更者名 E ← 修正終了点コメント
単数行コメント
SQL 内で使用する単数行コメント(カラムコメントなど)には、「
--
」を使用する。
複数行コメント
「 /*
*/
」を使用する。下記に例を示す。
なお、前述で触れたとおり、SQL
ファイルの先頭にコメントを記述することは禁止とする。
良い例:
/**********************************************************************/
/*
* コメントを始めるスラッシュとアスタリスクは、それだけを1行に置く。
* それから、コメント・ブロック内の各行は縦にアスタリスクを置き
* コメントがあることを強調する。
* 最後に、アスタリスクとスラッシュは、それだけを1行に置く。
*/
/**********************************************************************/
複数行コメントアウト
複数行をコメントアウトする場合は、各行を「--
」でコメントアウトする。
「 /*
*/
」を使用すると、その中に「
/*
*/
」が存在した場合、コメントアウトが途中で切れてしまう恐れがあるため、
使用しない。
論理名の記載
SELECT
・INSERT
・UPDATE
・MERGE
のカラム名記述箇所には単数行コメントでカラムの論理名を記載する。
SELECT
・INSERT
・UPDATE
・DELETE
・MERGE
のテーブル名記述箇所には単数行コメントでテーブルの論理名を記載する。
論理名は ERD 等で定義された論理名と必ず一致させること。
結合方法は ANSI 形式(~outer join
~)ではなく Oracle
形式(+)
を使用する。
原則として(+)
は条件文の右にくるカラムに付与する。
良い例:
= T2.COL2(+) T1.COL1
代入や WHERE 句の条件設定などでデータ・タイプが異なる場合、明示的にタイプ変換を行う。(暗黙の型変換は使用しない)
「等しくない」を示す演算子は「!=
」を利用する。「<>
」「^=
」も動作するが統一の観点から利用しない。
ORDER BY
数字の構文は使用せずに、カラム名を記載する。
GROUP BY
数字の構文は使用せずに、カラム名を記載する。
集約関数を利用する場合は必ず記載すること。(省略可能であっても省略しない)
EXISTS 句を記載する際、サブクエリになる SELECT
句の指定は定数「1
」とする。
「*
」(ワイルドカード)や「'X'
」は統一の観点から利用しない。
また「*
」(ワイルドカード)についてはパフォーマンスの観点からも禁止とする。
良い例:
WHERE
EXISTS(
SELECT
1
FROM
FOO FWHERE
= M.KEY
F.COL1 )
トップレベルの SELECT
句には必ずAS
句を記載し別名を付ける。
同一の名前であっても AS 句を付与する。
また、「AS
」は省略可能であるが、省略はしないこと。
論理名の記載
WHERE
句でカラムと式を比較する際は左辺がカラムになるように記載すること。
良い例:
WHERE
= 1
TBL.COLUMN1 AND TBL.AMOUNT2 > TBL.AMOUNT3 + TBL.AMOUNT4
条件式の順序
原則として、WHERE 句で条件式を列挙する際、下記の順序を守ること。
良い例:
FROM
-- A_TABLE
A_TABLE A -- B_TABLE
, B_TABLE B -- C_TABLE
, C_TABLE C WHERE
-- A_TABLEの絞り込み
= ?
A.KEY1 AND A.KEY2 = ?
-- B_TABLEの絞り込み
AND B.KEY1 = ?
AND B.KEY2 = ?
-- B_TABLEの結合条件
AND B.COL1 = A.COL1
-- C_TABLEの絞り込み
AND C.KEY1 = ?
AND C.KEY2 = ?
-- C_TABLEの結合条件
AND C.COL1 = A.COL1
AND C.COL2 = A.COL2
AND C.COL3 = B.COL3
レコード数を数える COUNT
文の記述はCOUNT(*)
と記述する。
COUNT(1)
・COUNT('X')
・COUNT(KEY1)
という記載は NG。
本章ではパフォーマンス性を高めることを目的としたコーディング規約について記載する。
検索処理におけるコーディング規約を下記に示す。
中間一致、後方一致検索はインデックスを利用できないため避ける
検索条件で=
(等号)を使用できる場合は必ず使用する
A=1 or A=2
とする方がA>0 and A<3
などと記述するのよりパフォーマンス上優位な場合が多い。
これは A
にインデックスがある場合、=
であれば、インデックスが有効に使われるためである。
可能な限り検索条件にパーティションキーの値を指定する
全列ワイルドカード「*
」の使用はせず、カラム名を明記する
インデックスによる検索を指定したい場合、下記の記載を行わない
インデックスカラムを含む演算に対して条件指定
悪い例:
+ 1 > 100 /* NGパターン 右辺で演算してください */ TBL1.COL1
良い例:
> 100 - 1 TBL1.COL1
インデックスカラムに関数を通した値に対して条件指定
悪い例:
/* NGパターン 右辺に関数を通してください */
TO_CHAR(TBL1.COL1, 'YYYYMMDD') > '20151231'
良い例:
>= TO_DATE('20160101', 'YYYYMMDD') TBL1.COL1
インデックスカラムをOR
で条件指定(禁止ではないが原則行わない)
悪い例:
(/* NGパターンINDEXが利用されない場合があります。他の方法を検討してください */
= 1
TBL1.COL1 OR TBL1.COL1 = 2
)
挿入処理におけるコーディング規約を下記に示す。
*
」の使用はせず、カラム名を明記する。更新処理におけるコーディング規約を下記に示す。
削除処理におけるコーディング規約を下記に示す。
WITH 句の誤った使い方はパフォーマンスの劣化を招くため、WITH 句を利用する場合は DBA に相談する。
DISTINCT
は、暗黙のソート処理が行われる可能性があるため性能劣化につながる。
EXISTS 句の使用・代替を検討すること。
悪い例:
SELECT
DISTINCT
NO AS DEPT_NO
D.AS DEPT_NAME
, D.NAME FROM
DEPARTMENT D
, EMPLOYEE EWHERE
NO = E.DEPT_NO -- 社員が一人以上属している部門を取得 D.
良い例:
SELECT
NO AS DEPT_NO
D.AS DEPT_NAME
, D.NAME FROM
DEPARTMENT DWHERE
EXISTS(
SELECT
1
FROM
EMPLOYEE EWHERE
NO = E.DEPT_NO -- 社員が一人以上属している部門を取得
D. )
IN 句は最大 1000 個まで指定できるが、200 個程度でも ORA
エラーが発生するケースがある。
また IN 句の少しだけ異なる SQL が大量に発行されると CPU
高騰やメモリ枯渇を招く。
従って 100 を超えるような長い IN 句は使用せず、一時表を利用して
IN (SELECT ・・・ FROM 一時表)
のように書き換える。
原則NOT IN(SELECT~)
は使用せずに、NOT EXISTS (SELECT~)
を使用する。
NOT IN
句は、内部的にソートマージの結合をすることでテーブルをフルスキャンする場合があるため、性能が悪化する可能性がある。
UNION
はDISTINCT
処理が含まれパフォーマンス上問題があるため、UNION ALL
を使用する。
パラレルヒント句は DB 負荷が高いため、原則使用禁止とする。付与したい場合は DBA に相談する。
SELECT FOR UPDATE
はNO WAIT
または「WAIT
秒数指定」を必ず付ける。WAIT
指定なしの場合はロックが解除されてもプログラムに制御が返らないことがある。SELECT FOR UPDATE
で複数行にロックをかける場合、同時実行されるとデットロックを起こす可能性があるため、1件のロックでない場合はORDER BY
を指定する。分析関数の使用は可能だが、性能悪化を招く恐れがあるため、特性を知らない方は DBA に相談する。
インデックスの必要性については DBA で最終判断するため、必要とする場合は DBA へ相談する。
外部結合する際、内部表(駆動表)はなるべく想定件数の少ない表にする。