每个初学者都会犯的 7 个 SQL 错误(以及如何纠正它们)
我还记得第一次 SQL 查询返回零结果时的情景。我检查了表格,核对了列名,并重新阅读了三次查询。一切看起来都很完美。但数据库却不同意,我也不知道为什么。
原来,我写的是WHERE manager_id = NULL
,而不是WHERE manager_id IS NULL
。一个小字让我花费了一个小时的调试时间。
如果你正在学习 SQL,可能也会遇到类似的挫折。好消息是什么?你犯了每个初学者都会犯的错误。好消息呢?只要你知道要注意什么,这些错误就很容易解决。
在本指南中,我将带你了解绊倒初学者的 7 个最常见的 SQL 错误、它们发生的原因,以及准确的修正方法。最后,你将避免数小时的挠头调试,从第一天起就能编写出更简洁、更可靠的查询。
错误 1:使用=
NULL
代替IS NULL
问题所在
这是初学者最容易犯的错误,而且非常简单。当你想查找缺失值或未定义值的记录时,你的第一反应可能是编写查询:
sql
SELECT * FROM employees
WHERE manager_id = NULL;
该查询运行时不会出错,但即使表中存在 NULL 值,也总是返回零结果。为什么会这样?因为在 SQL 中,NULL
代表 "未知",而且无法使用等式来比较未知值。
解决方法
始终使用IS
NULL 检查 NULL 值:
sql
SELECT * FROM employees
WHERE manager_id IS NULL;
使用IS NOT NULL
查找有值的行:
sql
SELECT * FROM employees
WHERE email IS NOT NULL;
**专业提示:**记住,NULL = NULL
返回NULL
(而不是 TRUE),在 WHERE 子句中被视为 FALSE。NULL 不等于任何东西,甚至不等于它本身。
错误 2:忘记给字符串加上引号
问题所在
另一个常见的绊脚石是:忘记用引号将文本值包住。你可能会写
sql
SELECT * FROM products
WHERE category = Electronics;
这会产生错误,因为 SQL 认为Electronics
是列名,而不是文本值。数据库会查找一个不存在的名为 "Electronics "的列。
解决方法
始终用单引号括起字符串字面量:
sql
SELECT * FROM products
WHERE category = 'Electronics';
数字不需要引号:
sql
WHERE price > 100 -- Correct (number)
WHERE status = 'active' -- Correct (string)
**常见陷阱:**不要对字符串使用双引号--在标准 SQL 中,双引号用于标识符(表/列名),而不是值。
错误 3:混淆 AND/OR 逻辑而不使用括号
问题所在
在组合多个条件时,初学者通常会写出这样的查询:
sql
SELECT * FROM products
WHERE category = 'Electronics'
OR category = 'Computers'
AND price < 500;
您可能希望返回所有低于 500 美元的电子产品和计算机。但由于AND 的
优先级高于OR
,SQL 会将其读作
"获取所有电子产品(任何价格)或(500 美元以下的计算机)"
这会返回你不想要的昂贵的电子产品。
解决方法
始终使用括号来清楚地表明你的意图:
sql
SELECT * FROM products
WHERE (category = 'Electronics' OR category = 'Computers')
AND price < 500;
现在,两个类别都必须低于 500 美元,这正是您想要的。
**经验法则:**无论何时混合AND 和
OR
,都要使用小括号--即使你了解优先级。这样可以防止出错,并使查询具有可读性。
错误 4:在生产代码中使用SELECT *
问题所在
在探索数据时,键入SELECT *
非常方便--它可以显示所有内容:
sql
SELECT * FROM customers;
但在生产代码中,这却是性能杀手。你在检索不需要的列,浪费内存和网络带宽。更糟糕的是,如果以后有人向表中添加列,你的应用程序就会突然收到无法处理的额外数据。
解决方法
只明确列出需要的列:
sql
SELECT customer_id, first_name, email
FROM customers;
优点
- 查询执行速度更快
- 降低内存使用率
- 代码自文档化(准确显示使用的内容)
- 面向未来,防止表模式发生变化
**何时使用 SELECT *?**仅用于快速数据探索或测试,切勿在应用代码中使用。
错误 5:使用 LIMIT 而不使用 ORDER BY
问题所在
您想查看一些示例记录,所以您写道:
sql
SELECT * FROM orders
LIMIT 10;
这看起来不错,但如果不使用ORDER BY
,就会得到随机记录。运行两次,你可能会看到不同的结果。这样就无法进行调试,而且会产生不一致的应用程序行为。
修复方法
使用LIMIT
时,始终添加ORDER BY
:
sql
SELECT * FROM orders
ORDER BY order_date DESC
LIMIT 10;
现在你可以持续获得 10 个最新订单。
使用案例:
- 前 N 个查询:"获取 5 名薪资最高的员工
- 分页:"显示产品的第 2 页
- 最近的项目"显示最新的 20 篇文章
错误 6:在计算中忽略 NULL
问题所在
您是这样计算折扣价的:
sql
SELECT
product_name,
price,
discount,
price - discount AS sale_price
FROM products;
在遇到折扣为 NULL 的产品之前,计算都很顺利。整个计算返回 NULL,因为对 NULL 进行任何算术运算都会产生 NULL。
因此100 - NULL = NULL
,而不是 100。
修复方法
使用COALESCE()
为 NULL 提供默认值:
sql
SELECT
product_name,
price,
discount,
price - COALESCE(discount, 0) AS sale_price
FROM products;
如果存在折扣,COALESCE(discount, 0)
将返回折扣;如果为 NULL,
则返回 0。
其他常见情况:
total_sales / COALESCE(order_count,1)
(避免除以零)COALESCE(middle_name,'')
(将 NULL 转换为空字符串)
错误 7:试图在 WHERE 中使用列别名
问题所在
您创建了一个计算列,并尝试用它进行筛选:
sql
SELECT
product_name,
price * 1.1 AS price_with_tax
FROM products
WHERE price_with_tax > 100;
错误!SQL 说price_with_tax
不存在。这让初学者感到困惑,因为别名就在 SELECT 中。
解决方法
SQL 按特定顺序评估子句:WHERE
运行在SELECT
之前,因此当过滤发生时,别名还不存在。
在 WHERE 中重复计算:
sql
SELECT
product_name,
price * 1.1 AS price_with_tax
FROM products
WHERE price * 1.1 > 100;
**好消息:**您可以在ORDER BY
中使用别名,因为它在 SELECT 之后运行:
sql
SELECT
salary * 12 AS annual_salary
FROM employees
ORDER BY annual_salary DESC; -- This works!
结论:从第一天起就编写更好的 SQL
在初学者花费在 SQL 上的调试时间中,这七个错误可能占了 80%。好消息是什么?现在你知道了它们,就能避免数小时的挫败感。
快速回顾:
- 使用
IS NULL
,绝不= NULL
- 用单引号包住字符串
- 在 AND/OR 逻辑中使用小括号
- 避免在生产中使用
SELECT *
- 始终将 LIMIT 与 ORDER BY 搭配使用
- 在计算中处理 NULL 值
- 不要在 WHERE 中引用别名
掌握 SQL 的秘诀不是死记硬背语法,而是了解这些常见陷阱以及如何避免它们。在练习时,请随身携带本指南,这样从第一天起,你就能编写出更简洁、更可靠的查询。
**下一步:**试着针对每个错误编写 10 个练习查询。练习得越多,这些模式就会成为你的第二天性。
实践练习
尝试修正这个查询--它包含本文中的 3 个错误:
sql
SELECT * FROM employees
WHERE department = Sales
OR salary > 50000
AND manager_id = NULL
LIMIT 5;
答案:
- 缺少引号:
销售
- 缺少括号:
(部门 = '销售' 或工资 > 50000)
- 错误的 NULL 检查:
IS NULL
- 奖励:将
ORDER BY
添加为 LIMIT
你都找到了吗?