如何写好 SQL 代码?

如何写好 SQL 代码?

想要锻炼你的编程技能,最简单但最有效的方法之一,就是让你的代码更具可读性(readable)

让你的代码具有可读性,可以使你的代码更易于解释、更容易重现、而且更容易调试。提高可读性的最佳方法就是坚持执行一系列的规则或标准,以它保持一致和干净。

因此,在本文中,我将给你分享编写优秀的 SQL 代码的八个小技巧。如果你想了解更多SQL相关内容,可以阅读以下这些文章:
3年SQL经验,我总结了十条技巧
你知道吗?SQL也能做机器学习!
实用SQL函数清单——教你用SQL清理数据
手把手教你用Python创建SQL数据库!

1将关键字符和函数大写

让我从一个你可能已经在做的简单技巧开始,如果你已经这样做了,那这很好,但是你会惊讶有很多人不知道这点:当涉及到关键字和函数的时候,请确保它们是大写的!

虽然这看着像是在吹毛求疵,但这样的技巧会让你的代码清晰十倍。

不要这样写:

select name, date_trunc(register_date, week) from customers

试着这样写:

SELECT name, DATE_TRUNC(register_date, WEEK) FROM customers

2缩进和对齐

让我们继续,下一个技巧主要集中在代码的缩进和对齐上。思考下面这两个例子——哪个更清晰?

SELECT name, height, age, salary, CASE WHEN age<18 THEN "child" ELSE
"adult" END AS child_or_adult
FROM People LEFT JOIN Income USING (name)
WHERE height<=200 and age<=65

还是:

SELECT
name
, height
, age
, salary
, CASE WHEN age < 18 THEN "child"
ELSE "adult"
END AS child_or_adult
FROM
People
LEFT JOIN
Income USING (name)
WHERE
height <= 200
AND age <= 65

很明显,第二个代码更容易阅读,这完全归功于它的编程格式。特别要注意第二个示例中代码是如何缩进和垂直对齐的。这可以让没见过你代码的人更容易阅读它。

当然,你不必遵循和上面一样的缩进和格式样式,重要的是要运用这个技巧,并在整个代码中使用相同的样式。

3为数据库/表格/行/列应用统一大小写模式

在编程中,有几种常见的大小写表达类型,这里举几例:

  • camelCase
  • PascalCase
  • snake_case

无论你个人的偏好是什么,在整个代码中保持一致的大小写非常重要。

不要:

SELECT
   firstName
 , LastName
 , child_or_adult
FROM
   customers

试着这样写

SELECT
first_name
, last_name
, child_or_adult
FROM
customers

4避免 SELECT * (select all)

这是一个重要的技巧,不仅适用于格式的优化,还可以对你的查询优化。

即使你几乎使用了表格中的每一列,你最好还是写出需要的列。为什么呢?随着表的发展和更多列的添加/更改,指定你需要的列名能避免未来潜在的识别错误。

不要:

SELECT
*
FROM
customers

尝试用:

SELECT
name
, height
, age
, salary
FROM
customers

5使用公用表表达式,将代码模块化

使用公用表表达式(common table expressions或 CTE)对模块化和分解代码很有用 – 你可以把它想象成把文章分解为多个段落,方式是类似的 。

使用前:

SELECT 
   name
 , salary
FROM 
   People
WHERE 
   name IN (SELECT DISTINCT 
              name 
           FROM 
              population 
           WHERE 
              country = "Canada"
              AND city = "Toronto")
   AND salary >= (SELECT 
                     AVG(salary)
                  FROM 
                     salaries
                  WHERE 
                     gender = "Female")

使用后:

with toronto_ppl as (
   SELECT DISTINCT 
      name
   FROM 
      population
   WHERE 
      country = "Canada"
      AND city = "Toronto"
)
, avg_female_salary as (
   SELECT 
      AVG(salary) as avg_salary
   FROM 
      salaries
   WHERE 
      gender = "Female"
)
SELECT 
   name
,  salary
FROM 
   People
WHERE 
   name IN(SELECT name FROM toronto_ppl)
   AND salary >= (SELECT avg_salary FROM avg_female_salary)

现在,我们可以很容易看出 WHERE 函数正在过滤“多伦多(Toronto)”的名字。 CTE 非常有用,因为你不仅可以把代码分解成更小的块,还可以为每个 CTE 分配一个变量名(如上面的 toronto_ppl 和 avg_female_salary)

说到变量的名字,这就引出了我的下一点:

6描述性变量名

创建变量名时,你需要让它们描述它们所代表的内容。考虑我之前的例子:

with toronto_ppl as (
   SELECT DISTINCT 
      name
   FROM 
      population
   WHERE 
      country = "Canada"
      AND city = "Toronto"
)
, avg_female_salary as (
   SELECT 
      AVG(salary) as avg_salary
   FROM 
      salaries
   WHERE 
      gender = "Female"
)
SELECT 
   name
,  salary
FROM 
   People
WHERE 
   name IN(SELECT name FROM toronto_ppl)
   AND salary >= (SELECT avg_salary FROM avg_female_salary)


仅通过阅读上面变量名称本身,我们就可以清楚地看出,第一个 CTE 是从多伦多搜索人员,而第二个 CTE 是获取女性的平均工资。

下面举个反面的命名例子,(我以前见过)

with table_one as (
   SELECT DISTINCT 
      name
   FROM 
      population
   WHERE 
      country = "Canada"
      AND city = "Toronto"
)
, table_two as (
   SELECT 
      AVG(salary) as var_1
   FROM 
      salaries
   WHERE 
      gender = "Female"
)
SELECT 
   name
,  salary
FROM 
   People
WHERE 
   name IN(SELECT name FROM table_one)
   AND salary >= (SELECT var_1 FROM table_two)

7使用临时的函数简化代码

临时函数是一个很好的方法,它们可以:

1. 分解代码
2. 编写更简洁的代码
3. 并且能够重复使用。

考虑以下例子:

SELECT name
       , CASE WHEN tenure < 1 THEN "analyst"
              WHEN tenure BETWEEN 1 and 3 THEN "associate"
              WHEN tenure BETWEEN 3 and 5 THEN "senior"
              WHEN tenure > 5 THEN "vp"
              ELSE "n/a"
         END AS seniority 
FROM employees

相反,你可以利用临时函数来使用 CASE 子句。

CREATE TEMPORARY FUNCTION seniority(tenure INT64) AS (
   CASE WHEN tenure < 1 THEN "analyst"
        WHEN tenure BETWEEN 1 and 3 THEN "associate"
        WHEN tenure BETWEEN 3 and 5 THEN "senior"
        WHEN tenure > 5 THEN "vp"
        ELSE "n/a"
   END
);
SELECT name
       , seniority(tenure) as seniority
FROM employees

有了临时函数,查询本身就简单多了,而且可读性更强,还可以重复利用!

8有意义的注释

写注释时,有一个重要的规则:只在需要的时候才写。

通过前面的七个技巧(使用描述性名称、模块化代码、编写干净的代码等),你应该不需要写很多注释。

话虽如此,当代码本身无法解释你要实现的目标时,注释是有用的,并且可能是必需的。

下面是一个不好的注释例子:

# Getting names of people in Toronto, Canada
with table1 as (
   SELECT DISTINCT name
   FROM population
   WHERE country = "Canada"
         AND city = "Toronto"
)
# Getting the average salary of females
, table2 as (
   SELECT AVG(salary) as var1
   FROM salaries
   WHERE gender = "Female"
)

这些注释很无用,因为它告诉我的信息是可以通过阅读代码本身就知道的。请记住,注释更多要回答“为什么”你在做某事,而不是“你在做什么”。

谢谢你的阅读!记得订阅我们的公众号,不错过关于数据科学、分析技术技巧、面试求职的文章!你还可以订阅我们的YouTube频道,观看大量数据科学相关公开课:https://www.youtube.com/channel/UCa8NLpvi70mHVsW4J_x9OeQ;在LinkedIn上关注我们,扩展你的人际网络!https://www.linkedin.com/company/dataapplab/

原文作者:Terence Shin
翻译作者:Jiawei Tong
美工编辑:过儿
校对审稿:Jiawei Tong
原文链接:https://towardsdatascience.com/8-best-practices-for-writing-top-tier-sql-code-e1023996e459