代码样式指南主要用于规范项目中代码的一致性,使得代码简单、可读和易于维护,从一定程度上也影响代码的质量。一句话概括如何评价代码的质量:
衡量代码质量的唯一有效标准:WTF/min – Robert C. Martin
Google 针对大多数编程语言(例如:C/C++,Java,JavaScript,Python,R 等)都整理了相关的代码风格,但对于 SQL 这种用于数据库查询特殊目的的编程语言并没有整理对应的风格。同其他编程语言代码风格一样,没有哪种风格是最好的,只要在项目中采用统一合理的风格即可。
本文参考的 SQL 样式指南有如下几种:
本文给出的 SQL 样式指南基于上述几种进行整理和修改。
/* */
,行注释使用 --
,并在末尾换行。'
作为被引号包裹的标识符。,
后添加空格,避免行尾有空格。__
,这样很难辨认。避免川流式对齐代码。
/* Good */
SELECT id
FROM table_name
WHERE column = "test"
;
/* Bad */
SELECT id
FROM talbe_name
WHERE column = "test"
;
多个元素组合无法呈现在一行中时,应将第一个元素另起一行。
/* Good */
SELECT
CASE postcode
WHEN 'BN1' THEN 'Brighton'
WHEN 'EH1' THEN 'Edinburgh'
END AS city
FROM table_name
;
/* Bad */
SELECT
CASE postcode WHEN 'BN1' THEN 'Brighton'
WHEN 'EH1' THEN 'Edinburgh'
END AS city
FROM table_name
;
由括号构成的多行,结尾括号应单独一行。
/* Good */
SELECT id
FROM table_name
WHERE postcode IN (
'looooooooooooooooooooooooong_BN1',
'loooooooooooooooooooooooooog_EH1'
)
/* Bad */
SELECT id
FROM table_name
WHERE postcode IN ('looooooooong_BN1',
'looooooooong_EH1')
多行采用右侧逗号和左侧关键字连接。
/* Good */
SELECT
id,
name
FROM
talbe_name
WHERE
id > 1
AND name LIKE "%Tom%"
;
/* Bad */
SELECT
id
, name
FROM
table_name
WHERE
id > 1 AND
name LIKE "%Tom%"
;
根关键词建议单独一行,多个参数单独一行。
/* Good */
SELECT
id,
name
FROM
table_name
WHERE
id > 1
AND name LIKE "%Tom%"
LIMIT
10
;
/* Acceptable */
SELECT
id,
name
FROM table_name
WHERE
id > 1
AND name LIKE "%Tom%"
LIMIT 10
;
/* Bad */
SELECT id, name
FROM table_name
WHERE
id > 1
AND name LIKE "%Tom%"
LIMIT 10
;
使用 AS
明确指定别名,而非隐式。
/* Good */
SELECT
table_name_1.id AS user_id,
table_name_2.name AS user_name
FROM
looooooooong_table_name_1 AS table_name_1
LEFT JOIN
looooooooong_table_name_2 AS table_name_2
ON
table_name_1.id = table_name_2.id
;
/* Bad */
SELECT
table_name_1.id user_id,
table_name_2.name user_name
FROM
looooooooong_table_name_1 table_name_1
LEFT JOIN
looooooooong_table_name_2 table_name_2
ON
table_name_1.id = table_name_2.id
;
避免使用隐式关联。
/* Good */
SELECT
table_name_1.id,
table_name_2.name
FROM
table_name_1
INNER JOIN
table_name_2
ON
table_name_1.id = table_name_2.id
;
/* Bad */
SELECT
table_name_1.id,
table_name_2.name
FROM
table_name_1,
table_name_2
ON
table_name_1.id = table_name_2.id
;
明确关联类型。
/* Good */
SELECT
table_name_1.id,
table_name_2.name
FROM
table_name_1
INNER JOIN
table_name_2
ON
table_name_1.id = table_name_2.id
;
/* Bad */
SELECT
table_name_1.id,
table_name_2.name
FROM
table_name_1
JOIN
table_name_2
ON
table_name_1.id = table_name_2.id
;
明确指定分组列。
/* Good */
SELECT
submission_date,
normalized_channel IN ('nightly', 'aurora', 'beta') AS is_prerelease,
COUNT(*) AS count
FROM
telemetry.clients_daily
WHERE
submission_date > '2019-07-01'
GROUP BY
submission_date,
is_prerelease
;
/* Bad */
SELECT
submission_date,
normalized_channel IN ('nightly', 'aurora', 'beta') AS is_prerelease,
COUNT(*) AS count
FROM
telemetry.clients_daily
WHERE
submission_date > '2019-07-01'
GROUP BY
1, 2
;
尽量使用 Common Table Expressions (CTEs) 而非子查询。
/* Good */
WITH sample AS (
SELECT
client_id,
submission_date
FROM
main_summary
WHERE
sample_id = '42'
)
SELECT *
FROM sample
LIMIT 10
/* Bad */
SELECT *
FROM (
SELECT
client_id,
submission_date
FROM
main_summary
WHERE
sample_id = '42'
)
LIMIT 10
尽量在 CTEs 中处理查询而非主语句中。
/* Good */
WITH backings_per_category AS (
SELECT
...
), backers AS (
SELECT
backings_per_category.backer_id,
COUNT(backings_per_category.id) AS projects_backed_per_category
INNER JOIN ksr.users AS users ON users.id = backings_per_category.backer_id
GROUP BY backings_per_category.backer_id
), backers_and_creators AS (
...
)
SELECT * FROM backers_and_creators;
/* Bad */
WITH backings_per_category AS (
SELECT
...
), backers AS (
SELECT
backer_id,
COUNT(backings_per_category.id) AS projects_backed_per_category
), backers_and_creators AS (
...
)
SELECT *
FROM backers_and_creators
INNER JOIN backers
ON backers_and_creators
ON backers.backer_id = backers_and_creators.backer_id
!=
而不是 <>
表示不等于。BETWEEN
而不是多个 AND
语句。IN()
而不是多个 OR
语句。SELECT *
。a, b, c
。