ThinkPHP 7.3 不支持直接执行 SQL 文件或自动合并表,逻辑合并需用 Db::query() 执行 UNION 查询,物理合并需用 Db::execute() 执行 INSERT...SELECT,并推荐事务保障原子性;手动解析 SQL 文件风险极高,应避免。

ThinkPHP 7.3 本身不提供直接执行 SQL 文件或自动合并表的内置方法。所谓“合并表”,通常指两种场景:
- 逻辑合并(如 UNION 查询):把多个表的数据按字段结构一致的方式拼成一个结果集;
- 物理合并(如 INSERT INTO ... SELECT):把一张表的数据插入到另一张结构兼容的表中,实现数据归集。
下面分情况说明在 TP7.3 中如何安全、可靠地实现:
使用 Db::query() 执行 UNION 类查询(逻辑合并)
适用于字段名、类型、数量基本一致的多表横向合并:
use think\facade\Db;
$sql = "SELECT id, title, 'news' AS source FROM think_news
UNION ALL
SELECT id, title, 'article' AS source FROM think_article
ORDER BY id DESC
LIMIT 20";
$result = Db::query($sql);⚠️ 注意:
立即学习“PHP免费学习笔记(深入)”;
- 必须用
Db::query()(不能用execute),因为这是SELECT; -
UNION ALL比UNION性能更好(不去重),除非业务明确需要去重; - 字段别名(如
'news' AS source)建议统一,便于 PHP 层处理; - 表名若跨库,必须写全路径:
db1.think_news、db2.think_article。
使用 Db::execute() 执行 INSERT ... SELECT(物理合并)
适用于将表 A 的数据批量导入表 B(两表结构需兼容):
$sql = "INSERT INTO think_archive (id, title, content, create_time)
SELECT id, title, content, create_time
FROM think_news
WHERE status = 1 AND create_time < '2026-01-01'";
$affected = Db::execute($sql);
echo "成功归档 {$affected} 条记录";✅ 关键点:
- 必须用
Db::execute(),因属于写操作; -
SELECT子句字段顺序和类型要与INSERT INTO目标字段严格对应; - 建议加
WHERE条件控制范围,避免误操作; - 可配合事务确保原子性(尤其涉及多步操作时):
Db::transaction(function () {
Db::execute("INSERT INTO think_archive (...) SELECT ... FROM think_news WHERE ...");
Db::execute("DELETE FROM think_news WHERE ...");
});不推荐:用 PHP 读取 .sql 文件再执行
TP7.3 没有 Db::import() 或类似方法。手动读取 .sql 文件并 explode(';') 执行风险极高:
- 无法识别注释、多行语句、存储过程;
- 遇到
CREATE TABLE、DROP等 DDL 语句易破坏环境; - 参数绑定失效,SQL 注入风险陡增。
如确需批量初始化(如部署时建表+插数据),应:
- 将建表语句放在数据库迁移工具(如 Phinx)或手动执行;
- 插入数据改用模型
saveAll()或Db::execute()分批处理。
补充:用模型 + union() 方法(有限支持)
TP7.3 的查询构造器支持简单 union,但仅限同库、同连接下的子查询:
$news = Db::table('think_news')->field('id,title,create_time')->where('status', 1);
$article = Db::table('think_article')->field('id,title,create_time')->where('status', 1);
$list = $news->union($article)->order('id desc')->limit(20)->select();? 限制:
- 两个子查询必须字段数、类型、顺序一致;
- 不支持跨库(会强制加前缀,导致
db2.think_article变成prefix_db2.think_article报错); -
union()后不能再链式调用join()或复杂where。
不复杂但容易忽略



















