【SQL入门】深入讲解WHERE子句!通过可复制的范例掌握数据筛选精髓
对于制作网站或应用程序的Web开发者来说,当听到“数据库”或“SQL”时,是否会觉得这太专业、与你无关呢?但在现代Web开发中,SQL知识是一种可以将你的创造力提升到新高度的强大武器。
例如,在像WordPress这样的CMS系统中,文章数据和用户信息都保存在数据库中。如果你懂SQL,就可以实现诸如“只显示满足特定条件的文章”等高级自定义功能。此外,当你想通过用户行为记录分析热门内容,并基于数据改进网站时,SQL更是必不可少的工具。也就是说,SQL不再只是后端工程师的专属技能。
本文将重点介绍SQL中非常关键的 WHERE子句。它就像一张“魔法之网”,帮助你从海量数据中精准地捞取你所需要的信息。我们将从基础到进阶彻底讲解其用法,并附上大量“可复制、可立即运行”的示例代码,让初学者也能安心学习。动手实践,一起感受“数据尽在掌控”的乐趣吧!
从准备开始!搭建SQL学习的舞台——示例数据表
为了展开接下来的SQL学习之旅,我们先来准备一个名为users的示例数据表。你可以把它想象成某个虚拟Web服务的用户信息表。如果能理解每个字段(列)都表示什么信息,后续的学习将会更加顺畅。
数据表定义:users
id:用于唯一标识用户的编号(ID)name:用户的姓名(字符串)age:用户的年龄(数值)pref:用户所在的都道府县(字符串)points:用户持有的积分(数值)。该字段允许为空(NULL)。
在后面的“实战演练”中,这张表将会被自动加载。请先熟悉一下这张表的数据结构和内容。
-- 定义数据表结构
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50),
age INT,
pref VARCHAR(50),
points INT
);
-- 向数据表插入示例数据
INSERT INTO users (id, name, age, pref, points) VALUES
(1, '田中 太郎', 25, '东京都', 120),
(2, '铃木 一郎', 32, '大阪府', 85),
(3, '佐藤 花子', 28, '东京都', 300),
(4, '高桥 次郎', 45, '福冈县', 50),
(5, '伊藤 樱', 25, '北海道', NULL),
(6, '渡边 三郎', 32, '东京都', 150),
(7, '山本 四郎', 51, '大阪府', 210);
WHERE子句基础——使用简单条件筛选数据
WHERE子句用于紧跟在SELECT * FROM users这样的语句之后,基本格式为:WHERE 列名 运算符 值。比起文字解释,实际运行才更能理解其含义。我们来看看最基本的比较运算符。
=:查找完全匹配的数据
等号=是最基础的比较运算符。例如你想找出“年龄为25岁”的用户时就可以使用它。数值可直接写入,字符串则必须用单引号(')包裹。
SELECT * FROM users WHERE age = 25;
<> 或 !=:查找不匹配的数据
若要排除某个值,例如“非东京都用户”,可使用<>或!=来表示“不等于”的条件。
SELECT * FROM users WHERE pref <> '东京都';
> 和 >=:查找大于或大于等于的数据
要比较数值大小也很简单,例如查找“积分大于100”的用户就可使用>。
SELECT * FROM users WHERE points > 100;
如果你想包含边界值,比如“年龄大于等于32岁”的用户,请使用>=。注意是否包含边界值将影响查询结果。
SELECT * FROM users WHERE age >= 32;
WHERE子句进阶——使用复杂条件灵活控制数据
掌握基础后,我们就可以尝试进阶用法。通过组合多个条件或使用更多运算符,WHERE子句将展现出更强大的功能。
AND 和 OR:组合多个条件
AND用于提取同时满足多个条件的数据。例如“住在东京都且年龄小于30岁”的年轻用户。
SELECT * FROM users WHERE pref = '东京都' AND age < 30;
OR用于提取满足任一条件的数据。例如“住在大阪府或年龄大于等于50岁”的用户。
SELECT * FROM users WHERE pref = '大阪府' OR age >= 50;
IN:同时指定多个值
想要查找“居住在东京都、大阪府或福冈县”的用户时,虽然可以使用多个OR连接,但用IN语句会更简洁、可读性更高,且在部分数据库中还能提升性能。
SELECT * FROM users WHERE pref IN ('东京都', '大阪府', '福冈县');
`BETWEEN`:指定特定的范围
当你想筛选“年龄在30到50岁之间的用户”时,可以使用 `BETWEEN`。它的意思等同于 `age >= 30 AND age <= 50`,但语义更直观。请注意,`BETWEEN` 会包含指定的两个边界值(即大于等于与小于等于)。
SELECT * FROM users WHERE age BETWEEN 30 AND 50;
`LIKE`:模糊搜索的好帮手
`LIKE` 是一个可以执行部分匹配搜索的强大运算符,它通常配合“通配符”使用。
- `%`:匹配任意数量的任意字符(包括0个字符)
- `_`:匹配任意一个字符
例如,若要查找姓名中包含「ro」的用戶(中間匹配),請在目標字符串前後加上 `%`。
SELECT * FROM users WHERE name LIKE '%ro%';
若要查找姓氏以「Sato」開頭的用戶(前綴匹配),請這樣寫:
SELECT * FROM users WHERE name LIKE 'Sato%';
`IS NULL`: 搜索「沒有資料」
資料庫中的 `NULL` 表示「沒有資料」的特殊狀態,它與 `0` 或空字串(`''`)完全不同。要查找 `NULL`,必須使用特殊語法 `IS NULL`,不能用 `=`。以下為範例:查找沒有註冊點數的用戶。
SELECT * FROM users WHERE points IS NULL;
相反地,如果要查找不是 `NULL` 的資料(即有值),請使用 `IS NOT NULL`。
SELECT * FROM users WHERE points IS NOT NULL;
初學者常見的三大陷阱
雖然 WHERE 非常實用,但如果不注意,也容易陷入錯誤。我們來看三個重要的注意事項。
- `AND` 和 `OR` 的優先順序與括號 `()`
在 SQL 中,`AND` 的優先順序高於 `OR`。若不加括號,複雜條件可能導致錯誤行為。例如,想查詢「住在 Tokyo 或 Osaka 且年齡大於等於 30 歲的用戶」,就必須用括號將 `OR` 條件括起來,讓資料庫能正確理解。 - 注意字段的数据类型
查询条件中的值应与字段的数据类型匹配:字符串用引号括起来,如 `'text'`,数值则不需引号。有些数据库会自动做隐式类型转换,例如把 `'123'` 当作数字处理,但这样会影响性能,甚至导致错误结果。养成使用正确数据类型的习惯非常重要。 - `NULL` 并不等于 0
如前所述,`NULL` 是一种特殊状态。`points = 0` 和 `points IS NULL` 完全不同。例如,在统计积分人数时,`COUNT(points)` 不会统计为 `NULL` 的用户,而 `COUNT(*)` 会统计所有行。理解这一区别能帮助你避免统计误差。
-- 條件格式為 (A OR B) AND C
SELECT * FROM users WHERE (pref = 'Tokyo' OR pref = 'Osaka') AND age >= 30;
WHERE 的力量不仅限于 SELECT
WHERE 子句不仅适用于 `SELECT` 查询,还在 `UPDATE` 和 `DELETE` 操作中起到关键作用。
如果你执行了 `DELETE FROM users` 而忘记添加 WHERE 条件,后果将不堪设想 —— 整个表的数据都会被删除。所以在执行修改或删除前,务必先用 `SELECT` 查询确认目标是否正确。
-- 请先用 SELECT 确认目标数据
SELECT * FROM users WHERE id = 3;
-- 确认无误后,再执行 UPDATE
-- UPDATE users SET points = points + 50 WHERE id = 3;
【实战】在浏览器中运行 SQL!
终于等到这一步!复制下方代码,保存为 `sql-practice.html` 文件,然后在浏览器中打开。
这个页面会借助 JavaScript 的 `sql.js` 库,在浏览器中创建一个临时数据库。你可以将本文中的 SQL 语句复制到左侧的文本框中,然后点击“执行 SQL”按钮,在右侧查看结果。动手实验不同的 WHERE 条件,直观地理解它们的作用!
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>SQL 执行环境(WHERE子句实践)</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; display: flex; flex-direction: column; height: 100vh; margin: 0; background-color: #f9f9f9; }
.header { padding: 15px 20px; background-color: #fff; border-bottom: 1px solid #ddd; }
.main-content { display: flex; flex: 1; overflow: hidden; }
.container { flex: 1; display: flex; flex-direction: column; padding: 20px; overflow-y: auto; }
.container:first-child { border-right: 1px solid #ddd; }
h3 { margin-top: 0; color: #333; }
textarea { height: 200px; border: 1px solid #ccc; border-radius: 4px; padding: 10px; font-family: "SF Mono", "Fira Code", "Source Code Pro", monospace; font-size: 14px; margin-top: 10px; resize: vertical; }
button { background-color: #007bff; color: white; border: none; padding: 12px 18px; border-radius: 4px; cursor: pointer; margin-top: 10px; font-size: 16px; transition: background-color 0.2s; }
button:hover { background-color: #0056b3; }
table { border-collapse: collapse; width: 100%; margin-top: 10px; background-color: #fff; }
th, td { border: 1px solid #ddd; padding: 10px; text-align: left; }
th { background-color: #f2f2f2; font-weight: 600; }
#error { color: #d9534f; font-weight: bold; margin-top: 10px; white-space: pre-wrap; }
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/sql-wasm.js"></script>
</head>
<body>
<div class="header">
<h2 style="margin: 0;">SQL WHERE 子句练习区</h2>
</div>
<div class="main-content">
<div class="container">
<h3>输入 SQL</h3>
<textarea id="sql-input">-- 试着修改以下 SQL!
SELECT * FROM users WHERE pref = '东京都';</textarea>
<button onclick="executeSql()">执行 SQL</button>
<div id="error"></div>
</div>
<div class="container">
<h3>执行结果</h3>
<div id="result-table"></div>
</div>
</div>
<script>
let db;
async function initDb() {
try {
const config = { locateFile: filename => `https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/${filename}` };
const SQL = await initSqlJs(config);
db = new SQL.Database();
const initialSql = `
CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(50), age INT, pref VARCHAR(50), points INT);
INSERT INTO users (id, name, age, pref, points) VALUES
(1, '田中 太郎', 25, '东京都', 120),
(2, '铃木 一郎', 32, '大阪府', 85),
(3, '佐藤 花子', 28, '东京都', 300),
(4, '高桥 次郎', 45, '福冈县', 50),
(5, '伊藤 樱', 25, '北海道', null),
(6, '渡边 三郎', 32, '东京都', 150),
(7, '山本 四郎', 51, '大阪府', 210);
`;
db.run(initialSql);
executeSql();
} catch (e) {
document.getElementById('error').textContent = "数据库初始化失败:" + e.message;
}
}
function executeSql() {
const sqlInput = document.getElementById('sql-input').value;
const errorEl = document.getElementById('error');
const resultEl = document.getElementById('result-table');
errorEl.textContent = '';
resultEl.innerHTML = '';
try {
const results = db.exec(sqlInput);
if (results.length > 0) {
resultEl.appendChild(createTable(results[0]));
} else {
resultEl.innerHTML = '<p>SQL 执行成功,但没有返回任何结果(例如 UPDATE 语句等)。</p>';
}
} catch (e) {
errorEl.textContent = "SQL 错误:" + e.message;
}
}
function createTable(result) {
const table = document.createElement('table');
const thead = document.createElement('thead');
const tbody = document.createElement('tbody');
const headerRow = document.createElement('tr');
result.columns.forEach(col => {
const th = document.createElement('th');
th.textContent = col;
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
result.values.forEach(row => {
const tr = document.createElement('tr');
row.forEach(cell => {
const td = document.createElement('td');
td.textContent = cell === null ? 'NULL' : cell;
tr.appendChild(td);
});
tbody.appendChild(tr);
});
table.appendChild(thead);
table.appendChild(tbody);
return table;
}
initDb();
</script>
</body>
</html>
总结与下一步
本文从基础到实践快速讲解了 SQL 的 WHERE 子句。相信您已经体会到 WHERE 子句在数据筛选方面的强大与灵活。
掌握 WHERE 子句只是开始。如果您想进一步深入学习 SQL,建议挑战以下主题:
- 聚合函数(如 `COUNT`, `SUM`, `AVG`)与 `GROUP BY`:对数据进行分组并计算总和或平均值。
- `JOIN` 子句:连接多个表以提取更复杂的数据。
- 子查询:在查询中嵌套其他查询的高级技巧。
掌握这些知识后,您的数据处理能力将大幅提升,作为 Web 创作者的能力也会得到极大拓展。希望本文能成为您精彩冒险旅程的第一步!