综述
一般注意事项:
- 使用统一且描述性强的标识符和名字
- 合理使用空格和缩进增强可读性
- 日期格式符合ISO-8601标准(YYYY-MM-DD HH:MM:SS.SSSSS)
- 使用标准SQL函数而非特定供应商的函数,从而提升可移植性
- 保证简单明了,没有多余的SQL,例如:不必要的引号或括号等
- 必要时在SQL中加入注释,使用C风格的/* */或者—
例子如下:
SELECT file_hash -- stored ssdeep hashFROM file_systemWHERE file_name = \'.vimrc\';/* Updating the file record after writing to the file */UPDATE file_systemSET file_modified_date = \'1980-02-22 13:19:01.00000\',file_size = 209732WHERE file_name = \'.vimrc\';
要避免的写法:
- 驼峰命名:不好快速查询
- 描述性前缀或匈牙利标志法如 sp_或tbl
- 复数:尽可能使用自然的集合术语如用staff替代employees,用people替代individuals
- 带引号的标识符: 如果没有办法用别的那么要保证使用SQL-92双引号来保证可移植性
- 不要在SQL或基于数据的结构中使用面向对象设计原则
命名惯例
总概
- 保证名字唯一性且不为保留关键字
- 保证名字长度不超过30个字节,实际中只要不是用双字节字符就不会超过30
- 名字必须以字母开头不能以下划线结尾
- 名字中只使用字母,数字和下划线
- 避免连续使用多个下划线
- 命名中间的空格使用下划线替代 例如:first name写成first_name
表
- 使用集合名或者在没那么理想的情况下使用复数,如staff和employees
- 不要用tbl做前缀或任何描述性的前缀以及匈牙利标志法
- 表和该表的列不要同名
- 尽可能不要将两个表的名字连接起来做关系表的表名,例如与其使用cars_mechanics不如用services
列名
- 保证使用单数命名
- 尽量避免使用id作为表的主键名
- 列名不要和表名相同
- 尽量使用小写,除非是特殊情况,例如专有名词
别名和关联名
- 别名要和其所指向的对象或表达式相关联
- 一般来说,关联名应该是对象名的每个单词的首字母组成
- 如果已经有了相同的关联明则在其后添加数字
- 记得总是要加入AS关键字,使其更易于阅读
- 为计算出的数据(如SUM() 或 AVG())命名时,用一个将这条数据存在表中时会使用的列名。
如下:
SELECT first_name AS fnFROM staff AS s1JOIN students AS s2ON s2.mentor_id = s1.staff_num;SELECT SUM(s.monitor_tally) AS monitor_totalFROM staff AS s;
(注:连表查询时,使用别名;单表查询时不需要使用别名)
存储过程名
- 名字必须包含动词
- 不要使用sp_做前缀,或者其他描述性的前缀或者匈牙利标志法
统一的后缀
使用统一的后缀让SQL更易阅读
_id —— 独一无二的标识符,如主键。
_status —— 标志值或任何表示状态的值,比如 publication_status。
_total —— 总和或某些值的和。
_num —— 表示该字段包含数值。
_name —— 表示名字,例如 first_name。
_seq —— 包含一系列值。
_date —— 表示该列包含日期。
_tally —— 计数值。
_size —— 大小,如文件大小或服装大小。
_addr —— 地址,有形的或无形的,如 ip_addr
查询语句
保留字
- 保留关键字总是要大写,如SELECT和WHERE
- 最好是避免使用缩写的关键字而是使用全写(如最好使用ABSOLUTE而非ABS)
- 不要使用数据库专有的关键字,如果ANSI SQL关键字能达到相同的效果,尽量使用SQL原生的关键字提高可移植性
如:
SELECT model_numFROM phones AS pWHERE p.release_date > \'2014-09-30\';
空格
使用空格来排列代码让根关键字都排列在同一列上,从而让SQL能更好的阅读。
如下例:
(SELECT f.species_name,AVG(f.height) AS average_height, AVG(f.diameter) AS average_diameterFROM flora AS fWHERE f.species_name = \'Banksia\'OR f.species_name = \'Sheoak\'OR f.species_name = \'Wattle\'GROUP BY f.species_name, f.observation_date)
UNION ALL
(SELECT b.species_name,AVG(b.height) AS average_height, AVG(b.diameter) AS average_diameterFROM botanic_garden_flora AS bWHERE b.species_name = \'Banksia\'OR b.species_name = \'Sheoak\'OR b.species_name = \'Wattle\'GROUP BY b.species_name, b.observation_date)
下列情况中,总是要加空格
- 等号(=)前后
- 逗号(,)后
- 单引号(‘’)的前和后,中间内容的前后不加空格
如:
SELECT a.title, a.release_date, a.recording_dateFROM albums AS aWHERE a.title = \'Charcoal Lane\'OR a.title = \'The New Danger\';
换行(Line spacing)
下列情况需要换行
- AND或OR前
- 分号后
- 每个关键字定义之后
- 当把多行分为不同的逻辑组时在分号后换行
- 将代码分为多个相关部分时
让所有关键字右对齐,让所有值左对齐,从而在SQL语句中间空出一条缝隙,也方便查阅。例子如下:
INSERT INTO albums (title, release_date, recording_date)VALUES (\'Charcoal Lane\', \'1990-01-01 01:01:01.00000\', \'1990-01-01 01:01:01.00000\'),(\'The New Danger\', \'2008-01-01 01:01:01.00000\', \'1990-01-01 01:01:01.00000\');UPDATE albumsSET release_date = \'1990-01-01 01:01:01.00000\'WHERE title = \'The New Danger\';SELECT a.title,a.release_date, a.recording_date, a.production_date -- grouped dates togetherFROM albums AS aWHERE a.title = \'Charcoal Lane\'OR a.title = \'The New Danger\';
缩进
Joins
连表查询时JOIN关键字需再缩进一格,必要时要换行,如下:
SELECT r.last_nameFROM riders AS rINNER JOIN bikes AS bON r.bike_vin_num = b.vin_numAND b.engine_tally > 2INNER JOIN crew AS cON r.crew_chief_last_name = c.last_nameAND c.chief = \'Y\';
子查询
子查询也要另起一行,并且右对齐和其他查询和格式一样。如下:
SELECT r.last_name,(SELECT MAX(YEAR(championship_date))FROM champions AS cWHERE c.last_name = r.last_nameAND c.confirmed = \'Y\') AS last_championship_yearFROM riders AS rWHERE r.last_name IN(SELECT c.last_nameFROM champions AS cWHERE YEAR(championship_date) > \'2008\'AND c.confirmed = \'Y\');
推荐形式
- 尽量使用 BETWEEN 而非多个 AND 语句。
- 同样地,使用 IN() 而非多个 OR 语句。
- 当数据输出数据库时需要处理时,使用 CASE 表达式。CASE 语句能嵌套形成更复杂的逻辑结构。
- 尽量避免 UNION 语句和临时表。如果数据库架构能够不靠这些语句运行,就不要用这些语句。
SELECT CASE postcodeWHEN \'BN1\' THEN \'Brighton\'WHEN \'EH1\' THEN \'Edinburgh\'END AS cityFROM office_locationsWHERE country = \'United Kingdom\'AND opening_time BETWEEN 8 AND 9AND postcode IN (\'EH1\', \'BN1\', \'NN1\', \'KW1\');
创建语句
在 CREATE 定义中,定义的每个列要缩进 4 个空格。
选择数据类型
- 尽量不要使用供应商指定的数据类。这些类型不可移植,还可能无法在相同供应商的旧版本系统上使用。
- 只在真的需要浮点数运算的时候才使用 REAL 和 FLOAT 类型,否则使用 NUMERIC 和 DECIMAL 类型。浮点数舍入误差是个麻烦。
指定默认类型
- 默认值一定与列的类型相同 —— 如果一个列的类型是 DECIMAL 那么就不要使用 INTEGER 类型的值作为默认值。
- 默认值要紧跟类型声明并在 NOT NULL 声明前。
约束和键
选择键
- 键在某种程度上要有唯一性。
- 该值在不同表中的类型应该相同且尽量保证不会更改。
- 该值是否能通过某种标准格式(如 ISO 发布的标准)?最好遵循第2点
- 尽量让键简单,但在适当情况下要使用复合键就使用复合键。
当然,当需求变更时,键也要根据情况更新
定义约束
概述
- 表中至少有一个键是完整且可使用的
- 除了 UNIQUE 、PRIMARY KEY 和 FOREIGN KEY 之外,约束应该有特定的名字
排列和排序
- 在 CREATE TABLE 语句后先定义主键
- 约束的定义应该紧跟它相应的列的定义后。
- 如果该约束与多个列相关,那么让其离相关的列越近越好。实在不行就放在表定义的最后。
- 把应用于整个表的表级别的约束放在表定义的最后。
- 按照字母顺序排列定义,ON DELETE 排在 ON UPDATE 前。
- 把所有相关的语句对齐。比如,把所有 NOT NULL 定义对齐到同一列。这样能提高可读性。
校验
- 已知字符串的格式时,用 LIKE 和 SIMILAR TO 约束来保证完整性。
- 当数值的范围可以确定时,用范围 CHECK() 来防止错误的值进入数据库或在没有提示的情况下截断。大部分情况下至少要确认数值大于零。
- CHECK() 约束应该在单独的子句中以便 debug。
如:
CREATE TABLE staff (PRIMARY KEY (staff_num),staff_num INT(5) NOT NULL,first_name VARCHAR(100) NOT NULL,pens_in_drawer INT(2) NOT NULL,CONSTRAINT pens_in_drawer_rangeCHECK(pens_in_drawer >= 1 AND pens_in_drawer < 100));
列的数据类型
出于在数据库引擎之间达到最大程度兼容的目的,下面是一些建议使用的列数据类型。
Character types 字符型
CHAR
CLOB
VARCHAR
Numeric types 数值型
精确数值类型
BIGINT
DECIMAL
DECFLOAT
INTEGER
NUMERIC
SMALLINT
近似数值类型
DOUBLE PRECISION
FLOAT
REAL
Datetime types 日期时间类型
DATE
TIME
TIMESTAMP
Binary types 二进制类型
BINARY
BLOB
VARBINARY
Additional types 其他类型
Boolean
INTERVAL
XML
本文为自己整理使用,原文地址为:CSS/