PHP MySQL Where
在PHP MySQL查询中,WHERE子句用于过滤记录,只返回满足指定条件的记录。本教程将介绍如何在PHP中使用WHERE子句进行条件查询,包括各种操作符、逻辑运算符以及常见的条件过滤方法。
基本的WHERE子句
WHERE子句用于在SELECT、UPDATE或DELETE语句中过滤记录。
1. MySQLi面向对象方式
<?php
// 数据库连接参数
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
// 创建连接
$conn = new mysqli($servername, $username, $password, $dbname);
// 检查连接
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
// SQL查询语句 - 带有WHERE子句
$sql = "SELECT id, firstname, lastname FROM MyGuests WHERE lastname='Doe'";
$result = $conn->query($sql);
// 检查结果集
if ($result->num_rows > 0) {
// 输出每行数据
while (row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - 名: " . $row["firstname"] . " - 姓: " . $row["lastname"] . "<br>";
}
} else {
echo "0 结果";
}
// 关闭连接
$conn->close();
?>
2. MySQLi过程式方式
<?php
// 数据库连接参数
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
// 创建连接
$conn = mysqli_connect($servername, $username, $password, $dbname);
// 检查连接
if (!$conn) {
die("连接失败: " . mysqli_connect_error());
}
// SQL查询语句 - 带有WHERE子句
$sql = "SELECT id, firstname, lastname FROM MyGuests WHERE lastname='Doe'";
$result = mysqli_query($conn, $sql);
// 检查结果集
if (mysqli_num_rows($result) > 0) {
// 输出每行数据
while (row = mysqli_fetch_assoc($result)) {
echo "ID: " . $row["id"] . " - 名: " . $row["firstname"] . " - 姓: " . $row["lastname"] . "<br>";
}
} else {
echo "0 结果";
}
// 关闭连接
mysqli_close($conn);
?>
3. 使用PDO
<?php
// 数据库连接参数
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
// 尝试连接数据库
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname;charset=utf8mb4", $username, $password);
// 设置PDO错误模式为异常
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// SQL查询语句 - 带有WHERE子句
$sql = "SELECT id, firstname, lastname FROM MyGuests WHERE lastname='Doe'";
// 准备和执行查询
$stmt = $conn->query($sql);
// 设置获取模式为关联数组
$stmt->setFetchMode(PDO::FETCH_ASSOC);
// 获取所有结果
$results = $stmt->fetchAll();
// 输出结果
if (count($results) > 0) {
foreach ($results as row) {
echo "ID: " . $row["id"] . " - 名: " . $row["firstname"] . " - 姓: " . $row["lastname"] . "<br>";
}
} else {
echo "0 结果";
}
} catch(PDOException $e) {
echo "错误: " . $e->getMessage();
}
// 关闭连接
$conn = null;
?>
WHERE子句中的比较运算符
MySQL支持多种比较运算符,可以在WHERE子句中使用:
运算符 | 描述 | 示例 |
---|---|---|
= | 等于 | WHERE id = 5 |
<> 或 != | 不等于 | WHERE category != 'Books' |
> | 大于 | WHERE price > 100 |
< | 小于 | WHERE quantity < 50 |
>= | 大于或等于 | WHERE age >= 18 |
<= | 小于或等于 | WHERE discount <= 0.2 |
BETWEEN | 在某个范围内 | WHERE price BETWEEN 50 AND 100 |
LIKE | 搜索模式 | WHERE name LIKE 'A%' |
IN | 指定多个可能的值 | WHERE color IN ('Red', 'Green', 'Blue') |
IS NULL | 值为NULL | WHERE description IS NULL |
IS NOT NULL | 值不为NULL | WHERE description IS NOT NULL |
比较运算符示例
1. 使用大于(>)运算符
<?php
// 数据库连接代码...
// 查询年龄大于30的用户
$sql = "SELECT id, firstname, lastname, age FROM users WHERE age > 30";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while (row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - 姓名: " . $row["firstname"] . " " . $row["lastname"] . " - 年龄: " . $row["age"] . "<br>";
}
} else {
echo "0 结果";
}
?>
2. 使用BETWEEN运算符
<?php
// 数据库连接代码...
// 查询价格在50到100之间的产品
$sql = "SELECT id, product_name, price FROM products WHERE price BETWEEN 50 AND 100";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while (row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - 产品: " . $row["product_name"] . " - 价格: $" . $row["price"] . "<br>";
}
} else {
echo "0 结果";
}
?>
3. 使用LIKE运算符进行模糊查询
<?php
// 数据库连接代码...
// 查询名称以"A"开头的产品
$sql = "SELECT id, product_name FROM products WHERE product_name LIKE 'A%'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while (row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - 产品: " . $row["product_name"] . "<br>";
}
} else {
echo "0 结果";
}
// 查询名称包含"book"的产品(不区分大小写)
$sql = "SELECT id, product_name FROM products WHERE product_name LIKE '%book%'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while (row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - 产品: " . $row["product_name"] . "<br>";
}
} else {
echo "0 结果";
}
?>
4. 使用IN运算符
<?php
// 数据库连接代码...
// 查询类别为Books, Electronics或Clothing的产品
$sql = "SELECT id, product_name, category FROM products WHERE category IN ('Books', 'Electronics', 'Clothing')";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while (row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - 产品: " . $row["product_name"] . " - 类别: " . $row["category"] . "<br>";
}
} else {
echo "0 结果";
}
?>
5. 处理NULL值
<?php
// 数据库连接代码...
// 查询描述为NULL的产品
$sql = "SELECT id, product_name FROM products WHERE description IS NULL";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while (row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - 产品: " . $row["product_name"] . "<br>";
}
} else {
echo "0 结果";
}
// 查询描述不为NULL的产品
$sql = "SELECT id, product_name FROM products WHERE description IS NOT NULL";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while (row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - 产品: " . $row["product_name"] . "<br>";
}
} else {
echo "0 结果";
}
?>
逻辑运算符
MySQL支持以下逻辑运算符,用于组合多个条件:
运算符 | 描述 | 示例 |
---|---|---|
AND | 当所有条件都为真时返回记录 | WHERE price > 50 AND category = 'Books' |
OR | 当任一条件为真时返回记录 | WHERE category = 'Books' OR category = 'Electronics' |
NOT | 反转条件的结果 | WHERE NOT category = 'Clothing' |
逻辑运算符示例
1. 使用AND运算符
<?php
// 数据库连接代码...
// 查询价格大于50且类别为Books的产品
$sql = "SELECT id, product_name, price, category FROM products WHERE price > 50 AND category = 'Books'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while (row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - 产品: " . $row["product_name"] . " - 价格: $" . $row["price"] . " - 类别: " . $row["category"] . "<br>";
}
} else {
echo "0 结果";
}
?>
2. 使用OR运算符
<?php
// 数据库连接代码...
// 查询类别为Books或Electronics的产品
$sql = "SELECT id, product_name, category FROM products WHERE category = 'Books' OR category = 'Electronics'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while (row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - 产品: " . $row["product_name"] . " - 类别: " . $row["category"] . "<br>";
}
} else {
echo "0 结果";
}
?>
3. 组合使用AND和OR运算符
<?php
// 数据库连接代码...
// 查询类别为Books且价格大于50,或者类别为Electronics的产品
$sql = "SELECT id, product_name, price, category FROM products WHERE (category = 'Books' AND price > 50) OR category = 'Electronics'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while (row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - 产品: " . $row["product_name"] . " - 价格: $" . $row["price"] . " - 类别: " . $row["category"] . "<br>";
}
} else {
echo "0 结果";
}
?>
使用预处理语句防止SQL注入
当WHERE子句中包含用户输入时,应始终使用预处理语句来防止SQL注入攻击。
1. MySQLi预处理语句
<?php
// 数据库连接代码...
// 假设这是从表单或URL获取的用户输入
$lastname = $_GET['lastname'] ?? '';
$age_min = $_GET['age_min'] ?? '0';
// 使用预处理语句
$stmt = $conn->prepare("SELECT id, firstname, lastname, age FROM users WHERE lastname = ? AND age >= ?");
$stmt->bind_param("si", $lastname, $age_min); // s = string, i = integer
// 执行查询
$stmt->execute();
// 获取结果
$result = $stmt->get_result();
if ($result->num_rows > 0) {
while (row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - 姓名: " . $row["firstname"] . " " . $row["lastname"] . " - 年龄: " . $row["age"] . "<br>";
}
} else {
echo "0 结果";
}
// 关闭语句
$stmt->close();
?>
2. PDO预处理语句
<?php
// 数据库连接代码...
// 假设这是从表单或URL获取的用户输入
$lastname = $_GET['lastname'] ?? '';
$age_min = $_GET['age_min'] ?? '0';
// 使用PDO预处理语句
$stmt = $conn->prepare("SELECT id, firstname, lastname, age FROM users WHERE lastname = :lastname AND age >= :age_min");
// 绑定参数
$stmt->bindParam(':lastname', $lastname, PDO::PARAM_STR);
$stmt->bindParam(':age_min', $age_min, PDO::PARAM_INT);
// 或者直接在execute中传递参数数组
// $stmt->execute([':lastname' => $lastname, ':age_min' => $age_min]);
// 执行查询
$stmt->execute();
// 设置获取模式
$stmt->setFetchMode(PDO::FETCH_ASSOC);
// 获取结果
while (row = $stmt->fetch()) {
echo "ID: " . $row["id"] . " - 姓名: " . $row["firstname"] . " " . $row["lastname"] . " - 年龄: " . $row["age"] . "<br>";
}
// 检查是否有结果
if ($stmt->rowCount() == 0) {
echo "0 结果";
}
?>
处理日期和时间条件
MySQL提供了多种函数来处理日期和时间条件。
<?php
// 数据库连接代码...
// 查询在特定日期之后注册的用户
$sql = "SELECT id, firstname, lastname, reg_date FROM users WHERE reg_date > '2023-01-01'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while (row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - 姓名: " . $row["firstname"] . " " . $row["lastname"] . " - 注册日期: " . $row["reg_date"] . "<br>";
}
}
// 使用NOW()函数查询今天注册的用户
$sql = "SELECT id, firstname, lastname, reg_date FROM users WHERE DATE(reg_date) = DATE(NOW())";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while (row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - 姓名: " . $row["firstname"] . " " . $row["lastname"] . " - 注册日期: " . $row["reg_date"] . "<br>";
}
}
// 查询过去7天内注册的用户
$sql = "SELECT id, firstname, lastname, reg_date FROM users WHERE reg_date >= DATE_SUB(NOW(), INTERVAL 7 DAY)";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while (row = $result->fetch_assoc()) {
echo "ID: " . $row["id"] . " - 姓名: " . $row["firstname"] . " " . $row["lastname"] . " - 注册日期: " . $row["reg_date"] . "<br>";
}
}
?>
子查询
子查询是嵌套在另一个SQL查询中的查询。在WHERE子句中使用子查询可以基于另一个查询的结果进行过滤。
<?php
// 数据库连接代码...
// 查询订单总金额大于平均订单金额的订单
$sql = "SELECT order_id, customer_id, total_amount FROM orders WHERE total_amount > (SELECT AVG(total_amount) FROM orders)";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while (row = $result->fetch_assoc()) {
echo "订单ID: " . $row["order_id"] . " - 客户ID: " . $row["customer_id"] . " - 总金额: $" . $row["total_amount"] . "<br>";
}
}
// 查询购买了特定产品的客户
$sql = "SELECT id, firstname, lastname FROM customers WHERE id IN (SELECT DISTINCT customer_id FROM orders WHERE order_id IN (SELECT order_id FROM order_items WHERE product_id = 10))";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while (row = $result->fetch_assoc()) {
echo "客户ID: " . $row["id"] . " - 姓名: " . $row["firstname"] . " " . $row["lastname"] . "<br>";
}
}
?>
WHERE子句最佳实践
- 始终使用预处理语句:当WHERE子句中包含用户输入时,使用预处理语句防止SQL注入
- 使用适当的索引:在WHERE子句中频繁使用的列上创建索引,以提高查询性能
- 避免在WHERE子句中对列进行函数操作:这会导致索引失效,例如:WHERE DATE(reg_date) = '2023-01-01'
- 使用合适的比较运算符:根据数据类型和查询需求选择合适的运算符
- 注意NULL值的处理:NULL值需要使用IS NULL或IS NOT NULL来检查,不能使用=或!=
- 使用括号明确逻辑顺序:当组合多个AND和OR条件时,使用括号明确逻辑顺序
- 优化LIKE查询:避免以通配符开头的LIKE查询,如LIKE '%keyword%',这会导致全表扫描
- 对于大范围筛选使用BETWEEN:当筛选范围值时,使用BETWEEN通常比使用>和<组合更高效
- 使用EXPLAIN分析查询性能:使用EXPLAIN语句分析WHERE子句的执行计划
- 限制返回的列数:只选择需要的列,而不是使用SELECT *
常见陷阱和错误
- 忘记处理SQL注入:直接将用户输入拼接到SQL查询中是非常危险的
- 错误处理NULL值:使用= NULL而不是IS NULL来检查NULL值
- 数据类型不匹配:比较不同数据类型的值时可能会导致意外结果
- 忽略大小写敏感性:MySQL默认情况下,字符串比较是不区分大小写的,但这取决于所使用的字符集和排序规则
- 逻辑运算符顺序错误:忘记使用括号导致逻辑顺序错误
- 过度使用OR条件:大量的OR条件可能导致查询性能下降,可以考虑使用IN运算符替代