查软删除记录时whereBetween不生效,根本原因是模型未启用SoftDeletes trait或deleted_at字段定义错误;需确认trait使用、字段为NULLABLE、加索引,并用withTrashed()或onlyTrashed()解除自动过滤。

查软删除记录时 whereBetween 不生效?先确认模型是否启用软删除
很多情况下 whereBetween('deleted_at', [...]) 查不到数据,根本原因不是写法错,而是模型压根没开启软删除。Laravel 只有在模型用了 SoftDeletes trait,并且数据库字段是 deleted_at(或自定义的)时,才会自动处理软删逻辑——但这个“自动处理”默认会把已删除记录从查询中过滤掉。
所以如果想查软删时间范围,必须先显式告诉 Eloquent:别给我自动过滤。
- 确保模型 use
Illuminate\Database\Eloquent\SoftDeletes - 检查数据库表中是否存在
deleted_at字段(类型应为datetime或timestamp,允许 NULL) - 若字段名不是
deleted_at,需在模型中定义const DELETED_AT = 'your_field_name';
查已删除记录的时间范围:用 withTrashed() + whereBetween
withTrashed() 是关键开关,它让 Eloquent 暂停对 deleted_at IS NULL 的自动 WHERE 过滤,这样你才能对 deleted_at 字段做任意条件操作。
比如查上周被软删除的用户:
use App\Models\User;
$users = User::withTrashed()
->whereBetween('deleted_at', [
now()->subWeek()->startOfDay(),
now()->subWeek()->endOfDay()
])
->get();
注意:withTrashed() 会同时包含未删除(deleted_at 为 NULL)和已删除的记录,所以如果你只想要「已删除」的,得额外加 whereNotNull('deleted_at')。
- 只查已删除的:用
onlyTrashed()替代withTrashed() - 如果要排除软删记录,但又想用
whereBetween查其他字段,不需要任何额外方法——默认行为就满足 -
whereBetween对 NULL 值不匹配,所以onlyTrashed()后再whereBetween是安全的
whereBetween('deleted_at', [...]) 在非软删模型里会报错或返回空
如果模型没 use SoftDeletes,但表里碰巧有 deleted_at 字段,直接写 whereBetween('deleted_at', [...]) 不会报错,但大概率返回空——因为该字段全是 NULL,而 whereBetween 要求两端都是非 NULL 值才可能命中。
更隐蔽的问题是:有些迁移里把 deleted_at 设成了 NOT NULL DEFAULT '0000-00-00 00:00:00',这会导致 whereBetween 行为异常(比如匹配到大量“假删除”记录),Laravel 软删除机制也完全失效。
- 检查字段定义:
SHOW COLUMNS FROM users LIKE 'deleted_at'; - 正确迁移写法应为:
$table->softDeletes();(生成deleted_at TIMESTAMP NULL) - 已有错误字段需手动修正:
ALTER TABLE users MODIFY deleted_at TIMESTAMP NULL;
性能注意:deleted_at 字段一定要加索引
软删除字段经常用于范围查询(比如按月统计删除量、清理过期软删数据),没索引的话,whereBetween('deleted_at', [...]) 会触发全表扫描,尤其在百万级用户表里,一次查询可能卡几秒。
加索引很简单,但容易漏:
Schema::table('users', function (Blueprint $table) {
$table->index('deleted_at');
});
注意不要加成唯一索引——因为大量记录的 deleted_at 是 NULL,MySQL 唯一索引只允许一个 NULL,会导致插入失败。
- 复合索引场景:如果常查
status和deleted_at组合,考虑INDEX(status, deleted_at) - 使用
onlyTrashed()时,Eloquent 生成的 SQL 是WHERE deleted_at IS NOT NULL,索引依然有效 - SQLite 用户注意:它的索引对 NULL 处理略有不同,建议升级到 Laravel 10+ 并测试实际执行计划


















