MySQL - IN 运算符
MySQL - IN 运算符
Section titled “MySQL - IN 运算符”IN 运算符:OR 的强大简写
Section titled “IN 运算符:OR 的强大简写”MySQL 中的 IN 运算符允许你在 WHERE 子句中指定多个值。它提供了一种简洁的方式来检查列的值是否与给定列表中的任何值匹配。它在功能上等同于一系列 OR 条件,但通常更具可读性,并且可能性能更好。
SELECT column_name(s)FROM table_nameWHERE column_name IN (value1, value2, ...);这比写 WHERE column_name = value1 OR column_name = value2 OR ... 要简洁得多。
让我们设置一个 CUSTOMERS 表。
CREATE TABLE CUSTOMERS( ID INT AUTO_INCREMENT PRIMARY KEY, NAME VARCHAR(100) NOT NULL, AGE INT NOT NULL, ADDRESS VARCHAR(255), SALARY DECIMAL(10, 2));
INSERT INTO CUSTOMERS(NAME, AGE, ADDRESS, SALARY) VALUES('Ramesh', 32, 'Ahmedabad', 2000.00),('Khilan', 25, 'Delhi', 1500.00),('Kaushik', 23, 'Kota', 2000.00),('Chaitali', 25, 'Mumbai', 6500.00),('Hardik', 27, 'Bhopal', 8500.00),('Komal', 22, 'Hyderabad', 4500.00),('Muffy', 24, 'Indore', 10000.00);要检索名为 ‘Khilan’、‘Hardik’ 或 ‘Muffy’ 的客户:
SELECT * FROM CUSTOMERSWHERE NAME IN ('Khilan', 'Hardik', 'Muffy');| ID | 姓名 | 年龄 | 地址 | 薪资 |
|---|---|---|---|---|
| 2 | Khilan | 25 | Delhi | 1500.00 |
| 5 | Hardik | 27 | Bhopal | 8500.00 |
| 7 | Muffy | 24 | Indore | 10000.00 |
用于排除的 NOT IN 运算符
Section titled “用于排除的 NOT IN 运算符”正如你所预料的,NOT IN 执行相反的操作。它选择所有列值与列表中任何值都 不 匹配的行。
示例:排除特定年龄
Section titled “示例:排除特定年龄”查找所有年龄不为 25、23 或 22 岁的客户:
SELECT * FROM CUSTOMERSWHERE AGE NOT IN (25, 23, 22);关于 NULL 的重要说明: 如果提供给 NOT IN 的列表中包含 NULL,或者被检查的列包含 NULL,则行为可能会与直觉相悖。col NOT IN (1, 2, NULL) 将永远不会为真,因为 col <> NULL 的结果是未知的。最好确保与 NOT IN 一起使用的列表和列不包含 NULL,或者明确地处理它们。
将 IN 与子查询结合使用
Section titled “将 IN 与子查询结合使用”IN 的一个强大特性是它能够与子查询一起使用。子查询必须返回单列,然后外部查询将查找与子查询结果集中任何值匹配的行。
示例:查找高收入城市的客户
Section titled “示例:查找高收入城市的客户”让我们找出所有居住在至少有一人收入超过 8000 美元的城市的客户。
-- 首先,子查询找到高收入者所在的城市。-- SELECT ADDRESS FROM CUSTOMERS WHERE SALARY > 8000.00; -> 返回 ('Bhopal', 'Indore')
-- 现在,在主查询中使用它。SELECT ID, NAME, ADDRESS FROM CUSTOMERSWHERE ADDRESS IN ( SELECT ADDRESS FROM CUSTOMERS WHERE SALARY > 8000.00);性能考量:IN 与 JOIN 与 EXISTS
Section titled “性能考量:IN 与 JOIN 与 EXISTS”虽然带有子查询的 IN 具有可读性,但它并非总是性能最佳的选择。现代 MySQL 优化器非常优秀,但从历史上看,JOIN 或 EXISTS 可能更快。
IN: 通常适用于小型、静态列表或子查询返回少量行的情况。JOIN: 当子查询返回大量结果集时,通常比IN性能更好,因为它能更有效地利用索引。上述查询可以改写为JOIN。EXISTS: 最适合当你只需要检查子查询中是否存在匹配行,而不关心实际值时。它可以在找到第一个匹配项时立即停止。
-- 使用 JOIN 的相同查询(通常性能更好)SELECT DISTINCT c1.ID, c1.NAME, c1.ADDRESSFROM CUSTOMERS c1JOIN CUSTOMERS c2 ON c1.ADDRESS = c2.ADDRESSWHERE c2.SALARY > 8000.00;最佳实践: 对于简单情况,IN 很好。对于复杂查询或性能关键路径,请始终使用 EXPLAIN 测试所有三种变体(IN、JOIN、EXISTS),以查看你的特定 MySQL 版本如何优化它们。
高级用法:IN 与行构造函数
Section titled “高级用法:IN 与行构造函数”你可以使用 IN 和行构造函数一次性检查多列的匹配项。这为复杂的条件提供了非常简洁的语法。
-- 查找年龄为 25 岁来自孟买,或年龄为 32 岁来自艾哈迈达巴德的客户SELECT NAME, AGE, ADDRESSFROM CUSTOMERSWHERE (AGE, ADDRESS) IN ((25, 'Mumbai'), (32, 'Ahmedabad'));安全:使用 IN 防止 SQL 注入
Section titled “安全:使用 IN 防止 SQL 注入”如果用户输入处理不当,IN 子句是 SQL 注入漏洞的常见来源。切勿 通过将用户提供的值直接拼接到 IN 列表中来构建查询。
// 危险 - 不要这样做!const user_ids = "1, 2, 3) OR 1=1 --";const sql = `SELECT * FROM users WHERE id IN (${user_ids})`; // 这将导致安全灾难始终使用带占位符的预处理语句。大多数数据库库都要求你动态生成正确数量的占位符(?)。
在客户端应用程序中实现 IN(安全地)
Section titled “在客户端应用程序中实现 IN(安全地)”以下是如何在现代 Node.js 中安全地使用带有动态值列表的 IN 子句。
Node.js(安全的动态 IN 子句)
此示例演示了从输入数组构建 `IN` 子句的正确、安全方法。它动态生成占位符,并将输入数组传递给 `execute` 方法,以实现安全的参数绑定。
```javascript// secureInClause.jsconst mysql = require('mysql2/promise');
async function getCustomersByIds(ids) { // 1. 验证和清理输入。确保 `ids` 是一个数字数组。 if (!Array.isArray(ids) || ids.length === 0) { console.log('未提供有效 ID。'); return; } const numericIds = ids.map(id => parseInt(id, 10)).filter(Number.isFinite); if (numericIds.length === 0) { console.log('未找到有效的数字 ID。'); return; }
let connection; try { const pool = mysql.createPool({ host: 'localhost', user: 'root', password: 'password', database: 'TUTORIALS' }); connection = await pool.getConnection();
// 2. 动态创建占位符 (?, ?, ...) const placeholders = numericIds.map(() => '?').join(',');
// 3. 创建安全的 SQL 查询 const sql = `SELECT * FROM CUSTOMERS WHERE ID IN (${placeholders})`;
// 4. 使用值数组执行。库会处理其余部分。 const [customers] = await connection.execute(sql, numericIds);
console.log('找到的客户:', customers);
} catch (error) { console.error('数据库查询失败:', error); } finally { if (connection) connection.release(); }}
// 使用 ID 数组的示例getCustomersByIds([2, 4, 6]);// 带有潜在不安全输入的示例getCustomersByIds(['1', '3', '5; DROP TABLE customers']);