在学习和实践SQL的过程中,难免会犯错误。重要的是要从错误中学习,避免在未来重复同样的错误。本文将介绍通过频繁练习SQL可以避免的一些常见错误以及如何解决这些问题。
为了更好地解释,考虑一个销售数据的示例,其中包含代表销售ID、销售金额和销售日期的列。
SalesId:此列代表特定产品的销售ID。
SalesAmount:此列代表该特定产品的销售金额。
SalesDate:此列代表销售发生的日期。
执行查询的一个关键点是查询的执行顺序,顺序如下,否则输出可能不是预期的,有时甚至会导致查询错误。
为了避免在执行大型查询时遇到麻烦,建议规划并执行命令。最不希望做的是执行一个包含太多嵌套循环的大型查询。
始终养成规划和构建查询格式的习惯,甚至可以使用样本数据测试查询。
通常,为表中的每一列选择正确的数据类型至关重要。但是,可能会发生溢出,情况可能不会很好看。此外,数据类型转换会增加查询执行时间,因此,如果可能的话,避免在查询中进行数据类型转换是一个好习惯。
使用select *查询所有列会提高查询的执行时间,对于大量数据来说是一个昂贵的操作。不使用select *主要是出于性能和安全考虑。
# 错误方式
SELECT * FROM Sales
# 正确方式
SELECT SalesID, SalesAmount FROM Sales
例如,如果想从销售表中获取销售ID,那么应该只选择SalesID列,而不是使用select *选择所有列,这将有助于快速执行查询。上述查询定义了每个列,并且限制了每条记录的大小。
Distinct语句通过删除表中的重复行来找到与所选列对应的唯一行。在SQL中,distinct子句是一个耗时的操作,但有一个简单的解决方案。
# 错误方式
SELECT count(distinct SalesID) FROM Sales
可以使用group by代替distinct来使过程更快更平滑。例如,以下查询找到销售详情表中唯一SalesID的计数。
# 正确方式
SELECT count(*) FROM (SELECT SalesID FROM Sales group by SalesID)
想象一下,运行一个大型查询,一个计算量大的查询,返回数百万(M)行,最后意识到计算的方式是错误的,这不是预期的输出。
# 错误方式
SELECT SalesID, SalesAmount FROM Sales
为了解决这个问题,使用TOP / LIMIT预览结果,以确保有预期的结果,而不是浪费时间在问题上。
# 正确方式
SELECT TOP 100 SalesID, SalesAmount FROM Sales
通常使用having子句对聚合列应用过滤器,如(sum, min, max等)操作,这些操作是使用group by操作创建的。但有时,使用‘having’子句而不是‘where’子句来过滤表中的数据。
# 错误方式
SELECT count(SalesId), SalesAmount, SalesDate FROM Sales group by SalesDate having EmployeeID = 5
例如,要找到拥有员工ID 5的总销售额,让在结果中使用group by。
# 正确方式
SELECT count(SalesId), SalesAmount, SalesDate FROM Sales where EmployeeID = 5 group by SalesDate
假设销售部门有多个部门,没有员工。让写一个查询来找出特定部门的员工数量。
SELECT s.SalesName, COUNT(*) as EmployeeCnt FROM SalesID s LEFT JOIN dept_emp de ON d.dept_no = de.dept_no GROUP BY d.dept_name
注意,如果没有在Dept_emp上进行左外连接,它将排除没有员工的部门,因为Dept_emp中没有与该dept_no相对应的记录。另一方面,如果不想在结果中包含这些幽灵部门,那么进行左连接将是多余的,浪费的。
尽管可以使用EXIST()和COUNT()来发现表中是否有特定记录,但使用EXIST()更有效。虽然COUNT()将搜索整个表以提供匹配记录的总数,但EXIST()只会运行直到它在表中找到记录的第一个条目,节省时间和计算能力,使能够优化SQL查询。
当有多个表连接时,执行查询时操作符的优先级非常重要。如果不遵循操作符的优先级,将无法获得预期的输出,因为查询的读取将会不同。例如,想要获取名为“Ana”或“Joey”的每个员工的详细信息,每个员工的薪水至少为10,000美元。
SELECT e.emp_no, e.first_name, e.last_name, s.salary FROM employees e JOIN salaries s ON e.emp_no = s.emp_no WHERE (e.first_name = "Ana" OR e.first_name = "Joey") AND s.salary >= 10000