如何使用Eloquent删除表中的所有行?

214

我的猜测是使用以下语法:

MyModel::all()->delete();

但是那行不通。我确定这很简单,但我已经搜索了相关文档,找不到答案!


在 Laravel 7 和 8 中,您可以这样做 - Binar Web
14个回答

413

MyModel::all()->delete()不能生效是因为all()实际上会触发查询并返回一个Eloquent对象的集合。

您可以使用truncate方法,这适用于Laravel 4和5:

MyModel::truncate();

删除整个表中所有行,而不记录单独的行删除。


18
注意:truncate()函数还会重置任何自动增量计数器(同时请注意,您无法截断存在外键约束的表格)。 - William Turrell
12
FYI:Truncate 操作不会触发删除事件。 - Fusion
1
如果你真的想使用 MyModel::all()->delete(),请使用 foreach (MyModel::all() as $e) { $e->delete() } - Ema4rl
truncate 可以删除整个表并重新创建,这比逐行删除要快得多。重置 AUTO_INCREMENT 计数器是新创建表的副作用。 - chilly
当您设置了外键时,truncate() 可能会失败。 - Adam
显示剩余2条评论

123

Laravel 5.2+的解决方案。

Model::getQuery()->delete();

只需获取带有表名的基本构建器并进行任何操作,这比其他方法更简洁。

Laravel 5.6 解决方案

\App\Model::query()->delete();

11
如果有其他人对于为什么这样工作感到困惑,Model类通过__call魔术方法将方法转发给Builder 这里。因为Model类本身有一个delete方法,调用Model::delete()会调用Model方法,但实际上您需要的是Builder方法。因此,要显式地获取builder,可以使用getQuery()方法。 - kevinAlbs
1
如果您需要删除相关的表格,这个操作也不会执行。 - Terje Nesthus
它将强制删除所有记录,无论软删除是否开启。 - shalini
2
Model::whereNotNull('id')->delete(); -- 当软删除开启时,将执行软删除。 - shalini

76

如果您禁用了foreign_key_checks(我假设您使用的是MySQL),则可以使用 Model::truncate()

DB::statement("SET foreign_key_checks=0");
Model::truncate();
DB::statement("SET foreign_key_checks=1");

2
在 Laravel 4 中,您可以使用 DB::unprepared()。 - swdev
2
你可以使用Schema::disableForeignKeyConstraints();和Schema::enableForeignKeyConstraints();。 - Eleazar Resendez

52

我已经看到种子文件中这两种方法都被使用过。

// Uncomment the below to wipe the table clean before populating

DB::table('table_name')->truncate();

//or

DB::table('table_name')->delete();

即使您想设置外键,第一个选项也不能使用。

无法截断引用了外键约束的表

因此,使用第二个选项可能是一个好主意。


3
“delete”显然与“truncate”不同。 - Joel Mellon
2
@sudopeople,指出区别会非常有帮助。我也可以将其添加到我的答案中 - giannis christofakis
4
TRUNCATE不能在事务中使用,因为它不受ROLLBACK的影响。在这种情况下,可以使用(new MyModel) - > newQuery() - > delete() 来实现相同的效果。 - hammurabi

15

我想为通过谷歌搜索进入此帖子的用户添加另一种选项。我需要完成这个操作,但是希望保留我的自动递增值,而truncate()会重置它。我也不想使用任何DB::,因为我希望直接对模型对象进行操作。所以,我选择了这个:

Model::whereNotNull('id')->delete();

显然该列必须确实存在,但在一个标准的、开箱即用的Eloquent模型中,id列存在且从未为null。我不确定这是否是最佳选择,但对于我的目的来说它是有效的。


Model::delete(); 将完成相同的事情。 - Leng
6
不幸的是,在Laravel 5.0中,Model::delete()会抛出异常:Non-static method Illuminate\Database\Eloquent\Model::delete() should not be called statically - Dave James Miller

14

简单解决方案:

 Mymodel::query()->delete();

这个问题的解决方案早在18个月之前就已经发布了。 - miken32
1
如果您的模型使用软删除概念,请使用 query()->forceDelete() - ibnɘꟻ

13

有一种间接的方法:

myModel:where('anyColumnName', 'like', '%%')->delete();

示例:

User:where('id', 'like' '%%')->delete();

Laravel查询构建器信息:https://laravel.com/docs/5.4/queries


1
@aschipfl 其实没有太多需要解释的。这段代码运行 SQL DELETE FROM users WHERE id LIKE '%%',它匹配表中的所有行,因此删除了所有内容。 - Hkan
这让我有了头绪。最终,我在另一个模型上进行了 pluck() 操作,以获取所需的 ID 数组,然后使用该数组使用 whereIn 方法从我的模型中删除所有记录:$itemsAllContentIDs = Item::where('user_id', $userId)->pluck('item_content_id')->all(); ItemsContent::whereIn('id', $itemsAllContentIDs)->delete(); - Keith DC

9

我无法使用Model::truncate(),因为会出现错误:

SQLSTATE[42000]: 语法错误或访问冲突: 1701 不允许截断一个被外键约束引用的表

不幸的是,Model::delete()也不起作用(至少在Laravel 5.0中):

非静态方法Illuminate\Database\Eloquent\Model::delete()不应从不兼容的上下文调用,假设$this

但这个可以工作:

(new Model)->newQuery()->delete()

如果您已经设置了软删除,那么这将软删除所有行。要完全删除所有行,包括软删除的行,您可以改为使用以下内容:

(new Model)->newQueryWithoutScopes()->forceDelete()

7
您可以尝试这个一行代码,它也保留了软删除: ```` 您可以尝试以下一行代码,它可以同时保留软删除: ````
Model::whereRaw('1=1')->delete();

6

truncate存在的问题是它暗示了立即提交操作,所以如果在一个事务中使用它,则有可能会发现表为空。最好的解决方案是使用delete

MyModel::query()->delete();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接