
本文介绍使用 mysql union all 按优先级(table1 → table2 → table3)查询具有相同字段结构的多张表,并通过预处理语句安全获取首条匹配记录,避免 sql 注入与冗余数据。
本文介绍使用 mysql union all 按优先级(table1 → table2 → table3)查询具有相同字段结构的多张表,并通过预处理语句安全获取首条匹配记录,避免 sql 注入与冗余数据。
在实际开发中,有时会因业务演进或数据分片将同类数据分散存储于多个结构完全一致的表中(如 table1、table2、table3),字段均为 id, title, description, category, date, thumbnail, admin。此时若需根据 id 查找首个匹配的记录(即优先查 table1,未命中再查 table2,最后 fallback 到 table3),直接使用笛卡尔积联查(如原始代码中的 SELECT * FROM table1, table2, table3 WHERE id=...)不仅逻辑错误(会产生交叉组合)、性能极差,还存在严重 SQL 注入风险。
✅ 正确做法是采用 UNION ALL + 子查询 + LIMIT 1 策略,结合显式优先级标记与参数化查询:
<?php
include('config/database.php');
$id = $_GET['single'] ?? null;
// 验证ID为合法整数,增强健壮性
if (!is_numeric($id) || (int)$id <= 0) {
die('Invalid ID');
}
$id = (int)$id;
$sql = "
SELECT * FROM (
SELECT 1 AS tnum, id, title, description, category, date, thumbnail, admin
FROM table1 WHERE id = ?
UNION ALL
SELECT 2 AS tnum, id, title, description, category, date, thumbnail, admin
FROM table2 WHERE id = ?
UNION ALL
SELECT 3 AS tnum, id, title, description, category, date, thumbnail, admin
FROM table3 WHERE id = ?
) AS x
ORDER BY tnum
LIMIT 1";
$stmt = $conn->prepare($sql);
$stmt->bind_param('iii', $id, $id, $id);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();
if ($row) {
$title = htmlspecialchars($row['title']);
$date = htmlspecialchars($row['date']);
$admin = htmlspecialchars($row['admin']);
$thumbnail = htmlspecialchars($row['thumbnail']);
$description = htmlspecialchars($row['description']);
$category = htmlspecialchars($row['category']);
// ✅ 数据已安全获取,可直接用于输出或进一步处理
} else {
// ❗ 处理未找到任何匹配的情况
echo "No record found for ID: " . $id;
}
?>? 关键说明:
- tnum 字段用于显式控制优先级:table1 标记为 1,table2 为 2,table3 为 3;ORDER BY tnum LIMIT 1 确保仅返回最高优先级的首条匹配结果;
- 所有列名在 UNION ALL 中必须显式列出且顺序一致(避免 SELECT * 在不同表间隐式顺序差异导致错位);
- 使用 mysqli::prepare() 和 bind_param() 彻底杜绝 SQL 注入,远优于原始代码中直接拼接 $_GET['single'];
- 添加 id 类型校验与 htmlspecialchars() 输出转义,兼顾输入安全与 XSS 防护;
- UNION ALL 比 UNION 更高效(不自动去重),符合“取首个匹配”的语义。
? 延伸建议:
若表数量增长或查询频率极高,应考虑重构为单表+分区(Partitioning)或引入唯一索引+路由层,而非长期依赖多表 UNION 查询。

















