1 目的
本规范的主要目的是希望规范数据库设计与开发,尽量避免由于数据库设计与开发不当而产生的麻烦;同时好的规范,在执行的时候可以培养出好的习惯,好的习惯是软件质量的很好保证。
2 适用范围
本规划的适用人员范围包括涉及数据库设计与开发的相关技术人员。
3 术语约定
本规范采用以下术语描述:
★规则:也称为强规范是编程时必须强制遵守的原则
★建议:编程时必须加以考虑的原则
★说明:对此规则或建议进行必要的解释
★示例:对此规则或建议从正、反两个方面给出
4 规范及建议
4.1 书写规范
4.1.1 SQL书写规范
规则1: 数据库代码中,关键字大写,其他内容小写;
示例:
如下代码不符合规范:(关键字未大写)
select last_name ,job_id
from employees;
如下代码符合规范:
SELECT last_name, job_id
FROM employees;
规则2:程序块应采用缩进风格书写,保证代码可读,风格一致,缩进格数统一为4格;
规则3:代码中需要空位时,统一采用英文空格键输入,不允许用TAB键 产生空位;
说明:不同的编辑器对TAB的空位格数设置不一致,会导致使用TAB键产生空位的代码格式混乱;
规则4:同一条语句占用多行时,每一行的开始应是关键字, 且关键字应和第一行左对齐,如确实不能从关键字分行,则分行处应对其上一行被分行的同类代码的最左边;
示例:
如下代码不符合规范(分行书写时,其余行未和第一行左对齐)
SELECT last_name,
job_id
FROM employees;
如下代码也不符合规范(分行时,不是从关键字分行)
SELECT last_name,
job_id FROM employees;
如下代码符合规范
SELECT last_name, job_id
FROM employees;
如下代码符合规范
SELECT last_name,
first_name,
job_id
FROM employees;
规则5:查询数据时,尽量不使用SELECT *,而是给出明确的字段,但该规则不包括SELECT COUNT(*)语 句;
示例
如下语句不符合规范(SELECT操作未给出字段)
SELECT *
FROM employees;
如下语句符合规范
SELECT last_name, first_name
FROM employees;
规则6:INSERT语句应该给出字段列表;
示例
如下语句不符合规范(INSERT操作未给出字段名称)
INSERT INTO employees
VALUES
(
'GUO',
'DAVID',
100
);
如下语句符合规范
INSERT INTO employees
(
last_name,
first_name,
job_id
)
VALUES
(
'GUO',
'DAVID',
100
);
规则7:从表中同一笔记录中获取记录的字段值,须使用一SQL语句得到,不允许分多条SQL语句;
示例
如下语句不符合规范(从同一个表中取出记录,分成两条语句分别扫描)
UPDATE employees_new
SET last_name=
(
SELECT last_name
FROM employees
WHERE job_id = 100
)
WHERE job_id = 100;
UPDATE employees_new
SET first_name =
(
SELECT first_name
FROM employees
WHERE job_id = 100
)
WHERE job_id = 100;
如下语句符合规范
UPDATE employees_new
SET first_name =
(
SELECT last_name
FROM employees
WHERE job_id = 100
),
last_name =
(
SELECT first_name
FROM employees
WHERE job_id = 100
)
WHERE job_id = 100;
规则8:SQL语句中的逗号后面应增加一个空格,以使得代码清晰;
示例
如下代码不符合规范(逗号后面没有空格)
SELECT last_name,job_id
FROM employees;
如下代码符合规则
SELECT last_name, job_id
FROM employees;
规则9:不允许将SQL语句写成一行,再短的SQL也应该在谓词处分行;
示例
如下代码不符合规范(未在谓词部分进行分行)
SELECT last_name, job_id FROM employees WHERE job_id = 1;
如下代码符合规范
SELECT last_name, job_id
FROM employees
WHERE job_id = 1;
规则10:运算符以及比较符左边或者右边只要不是括号,则空一格;
示例
如下代码不符合规范(运算符没有空格)
SELECT CURRENT_DATE+INTERVAL 1 DAY
FROM dual;
如下代码符合规范
SLEECT CURRENT_DATE + (INTERVAL 1 DAY)
FROM dual;
规则11:不同类型的操作符混合使用时,应使用括号明确的表达运算的先后关系;
示例
如下代码不符合规范(运算优先级关系易混淆)
SELECT a*b/c+d*e
FROM dual;
如下代码符合规范
SELECT ((a * b) / c) + (d * e)
FROM dual;
规则12:任何SQL书写单行不得超过120字符(含左边的缩进);
建议1:对于INSERT…VALUES和UPDATE语句,一行写一个字段,每个字段相对于INSERT语句空4格,字段后面紧跟注释(注释语句左对齐),VALUES和INSERT左对齐,左括号和右括号与INSERT、VALUES左 对齐;
示例:
如下代码不符合建议(字段未和INSERT语句空格)
INSERT INTO sm_user
(
user_id, --用户ID,主键
user_name, --用户名
login_name --登录名
)
VALUES
(
p_user_id,
p_user_name,
p_login_name
);
如下代码符合建议
INSERT INTO sm_user
(
user_id, --用户ID,主键
user_name, --用户名
login_name --登录名
)
VALUES
(
p_user_id,
p_user_name,
p_login_name
);
建议2:INSERT…SELECT 语句时,应使每行的字段顺序对应,以每行最多不超过4个字段,以方便代码阅读,括号的内容另起一行缩进4格开始书写,关键字单词左对齐,左括号、右括号另起一行与左对齐;
示例
如下代码不符合建议(字段未和括号分行)
INSERT INTO sm_duty_bak(duty_id, duty_name, created_by, creation_date,
last_updated_by, last_update_date, disable_date)
SELECT duty_id, duty_name, created_by, creation_date,
last_updated_by, last_update_date, disable_date
FROM sm_duty
WHERE duty_id=88;
如下代码符合建议
INSERT INTO sm_duty_bak
(
duty_id, duty_name, created_by, creation_date,
last_updated_by, last_update_date, disable_date
)
SELECT
duty_id, duty_name, created_by, creation_date,
last_updated_by, last_update_date, disable_date
FROM sm_duty
WHERE duty_id = 88;
说明:
1.SELECT 语句中每行的字段应与INSERT 语句对应。
2.INSERT 语句中换行的字段名应缩进并与上一行的第一个字段名对齐。
3.SELECT 语句中换行的字段名应缩进并与上一行的第一个字段名对齐。
4.1.2 存储过程书写规范
规则1:不允许将多行语句书写在同一行;
示例
如下代码不符合规范(将两行定义书写在同一行)
SET v_count = 1; SET v_creation_date = CURRENT_DATE;
如下代码符合规范
SET v_count = 1;
SET v_creation_date = CURRENT_DATE;
规则2:相对独立的程序块之间应加空行;
示例
如下代码不符合规范(变量定义和程序段之间无空行)
SET v_duty_id = 1;
IF (v_disabled_date > v_current_date) THEN
SELECT duty_name
into v_duty_name
FROM sm_duty
WHERE duty_id = :duty_id;
…
END IF;
如下代码符合规范
SET v_duty_id = 1;
IF (v_disabled_date > v_current_date) THEN
SELECT duty_name
into v_duty_name
FROM sm_duty
WHERE duty_id = :duty_id;
…
END IF;
规则3:当一个SQL 语句中涉及到多个表时,始终使用别名来限定字段名,这使其它人阅读起来更方便,避免了含义模糊的引用,其中能够通过别名清晰地判断出表名;
说明 : 别名命名时,尽量避免使用无意义的代号a、b 、c… , 而应该有意义( 如表mtl_system_items_b 对应别名为msi,po_headers_all 别名对应为pha)。
示例
如下语句不符合规范(未使用有明确含义的表别名)
SELECT a.wip_entity_name, a.wip_entity_id, a.date_released
FROM wip.wip_entities b,
wip.wip_discrete_jobs a
WHERE b.wip_entity_id = a.wip_entity_id
AND a.status_type = 3
如下语句符合规范
SELECT wdj.we_entity_name, wdj.wip_entity_id, wdj.date_released
FROM wip.wip_entities we,
wip.wip_discrete_jobs wdj
WHERE we.wip_entity_id = wdj.wip_entity_id
AND we.status_type = 3
规则4:确保变量/参数的类型和长度与表数据字段的类型和长度相匹配;
说明:如果与表数据列宽度不匹配,则当较宽或较大的数据传进来时会产生运行异常。
示例
如下代码不符合规范(假定表wap_user的字段user_name的定义为VARCHAR(10))
CREATE PROCEDURE ps_add()
BEGIN
DECLARE v_user_name VARCHAR(15);
UPDATE wap_user
SET user_name = v_user_name
WHERE sky_id = 100;
END;
如下代码符合规范
CREATE PROCEDURE ps_add()
BEGIN
DECLARE v_user_name VARCHAR(10);
UPDATE wap_user
SET user_name = v_user_name
WHERE sky_id = 100;
END;
规则5:存储过程代码块必须有注释;
建议1:减少控制语句的判断次数,比如在ELSE(IF…ELSE) 语句中,尽量将尽快能检测到结果的判断放在前面;
示例
如下语句不符合规范(假定v_count=1的条件大多数情况会满足)
IF (v_count = 0) THEN
NULL;
ELSEIF (v_count = 1) THEN
NULL;
END IF;
如下语句符合规范(假定v_count=1的条件大多数情况会满足)
IF (v_count = 1) THEN
NULL;
ELSEIF (v_count = 0) THEN
NULL;
END IF;
建议2:尽量避免使用嵌套的IF语句,在这种情况下应使用多个IF语句来判断其可能性;
示例
如下语句不符合规范(使用了嵌套的IF语句来进行判定)
IF v_count = 0 THEN
IF v_flag = 0 THEN
NULL;
ELSE
NULL;
END IF;
ELSE v_count = 1 THEN
IF v_flag = 0 THEN
NULL;
ELSE
NULL;
END IF;
END IF;
如下语句符合规范
IF (v_count = 0) AND (v_flag = 0) THEN
NULL;
ELSEIF (v_count = 0 ) AND (v_flag = 1) THEN
NULL;
ELSEIF (v_count = 1) AND (v_flag = 0) THEN
NULL;
ELSEIF (v_count = 1) AND (v_flag = 1) THEN
NULL;
END IF;
建议3:存储过程、函数、触发器、程序块中定义的变量和输入、输出参数在命名上有所区分;
说明:
用'v_ '开头代表程序块中定义的普通变量。
用'p_ '开头代表输入参数变量。
用'x_ '开头代表输入输出或输出参数变量。
用'cur_'开头代表游标变量。存放游标记录集。
4.2 对象命名规范
4.2.1 通用规则
规则1:任何数据库对象的命名,不得使用汉字;
示例
如下语句不符合规范(表明和字段名使用了汉字)
CREATE TABLE 用户
(
用户名 VARCHAR(100),
pass_word VARCHAR(16)
);
如下语句符合规范
CREATE TABLE wap_user
(
user_name VARCHAR(100),
pass_word VARCHAR(16)
);
规则2:库名,表名,字段名不得超过30个字符,用户名不得超过16个字符;
库名,表名,字段名最多支持64个字符,为了统一规范、易于辨识以及减少传输量,必须不超过30个字符。
示例
如下语句不符合规范(表命名达到65位长度)(修改)
CREATE TABLE wap_user_tel_number_region_user
(
user_name VARCHAR(100),
pass_word VARCHAR(16)
);
如下语句符合规范
CREATE TABLE wap_user_tel_number_region
(
user_name VARCHAR(100),
pass_word VARCHAR(16)
);
规则3:用户对象命名应全部为小写,使用下划线“_”分割;
说明:由于linux操作系统上的文件名是区分大小写的,所以MySQL表名是区分大小写的。
示例
如下语句不符合规范(表名应全部为小写)
CREATE TABLE Wap_user_tel_number_region
(
user_name VARCHAR(100),
pass_word VARCHAR(16)
);
如下语句符合规范
CREATE TABLE wap_user_tel_number_region
(
user_name VARCHAR(100),
pass_word VARCHAR(16)
);
规则4:命名应使用富有意义的英文,禁止使用拼音首字母, 一般情况下不建议使用拼音命名;
示例
如下语句不符合规范(表名使用了中文且字段使用了拼音首字母简写)
CREATE TABLE wap_yonghu
(
yhm VARCHAR(100),
pass_word VARCHAR(16)
);
如下语句符合规范
CREATE TABLE wap_user
(
user_name VARCHAR(100),
pass_word VARCHAR(16)
);
规则5:命名不得使用数据库保留字;
说明:使用了数据库保留字,会导致需要访问该对象时,需要代码做特别的转换才能访问
示例
如下代码不符合规范(假定user为数据库保留字)
CREATE TABLE wap_user
(
USER VARCHAR(100),
pass_word VARCHAR(16)
);
如下代码符合规范
CREATE TABLE wap_user
(
user_name VARCHAR(100),
pass_word VARCHAR(16)
);
4.2.2 表
规则1:同类业务的表,以相同的表示该类业务的英文开头;
说明:同类业务的表以相同的英文开头,在逻辑上清晰,且可避免维护过程中对该类表的误操作
示例
如下语句不符合规范(假定表wap_user和表user_login_log都属于wap类业务)
CREATE TABLE wap_user
(
user_name VARCHAR(100),
pass_word VARCHAR(16)
);
CREATE TABLE user_login_log
(
user_name VARCHAR(100),
login_date DATE
);
如下语句符合规范
CREATE TABLE wap_user
(
user_name VARCHAR(100),
pass_word VARCHAR(16)
);
CREATE TABLE wap_user_login_log
(
user_name VARCHAR(100),
login_date DATE
);
说明:各子系统不用加子系统名称前缀,如POS系统的表不用都加pos_前缀,如果遇到需要同步其他系统的表的表名与本系统的表名相同时,用子系统名称做后缀的形式重命名其他子系统表名,如POS系统需要同步MDM表bill_item_dtl而POS系统也存在这样的表名,则把MDM的表名重新命名为bill_item_dtl_mdm。
规则2:同类表,如果按照时间不同建立的表,后缀格式一般情况下应为’_YYYY[MM[DD]]’格式;
示例
如下语句不符合规范(将年份2010简写为10,导致含义模糊)
CREATE TABLE wap_user_login_1004
(
user_name VARCHAR(100),
login_date date
);
CREATE TABLE wap_user_login_1005
(
user_name VARCHAR(100),
login_date DATE
);
如下语句符合规范
CREATE TABLE wap_user_login_201004
(
user_name VARCHAR(100),
login_date DATE
);
CREATE TABLE wap_user_login_201005
(
user_name VARCHAR(100),
login_date DATE
);