Laravel 雄辩查询的高级 where
Posted
技术标签:
【中文标题】Laravel 雄辩查询的高级 where【英文标题】:Advanced where Laravel eloquent query 【发布时间】:2020-01-11 08:45:13 【问题描述】:我目前被困在一个 where
Laravel 查询上。问题是,我想根据给定表中的最新记录过滤一些数据。目前,我的查询如下所示:
$clients = $clients->whereDoesntHave('bill')->orWhereHas('bill', function ($query) use ($activeSchoolYear)
$query
->where('created_at', '<', Carbon::parse($activeSchoolYear->start));
)
$activeSchoolYear->start
是今天的日期。
如果我的 bills 表中有多个记录,就会出现问题。例如,如果我有两条不同日期的记录:
ID | Name | created_at |
1 | test | 2019-09-09 15:31:25|
2 | test2 | 2018-09-10 16:42:44|
查询仍然返回两个日期,即使其中一个为假。我认为该查询会查找数据库中的所有记录,并且仍然返回给定的用户,因为其中一个日期是正确的。我的问题是,是否可以仅针对数据库中的最新行。或者这不能使用 eloquent 来完成。任何帮助表示赞赏。
编辑:
正如@Caddy 建议的那样,我使用了查询范围,但我对其进行了一些修改:
public function scopeNoActiveBill($query)
return $query
->groupBy('created_at')->take(1)
->where('created_at', '<=', Carbon::create(2019, 9, 1));
我试图只从 bills 表中取出最后一行。然后,在控制器内部,这是我的查询:
$clients = $clients->whereDoesntHave('bill')
->orWhereHas('bill', function ($query) use ($activeSchoolYear)
$query->noActiveBill();
)
->whereHas('contracts', function ($query) use ($request)
$query
->where('contract_type', '<', 2)
->where('signed', 1)
->where('school_year_id', $request['school_year']);
);
因此,我希望既没有任何账单的客户,也希望有符合给定标准的账单的客户。如果客户只有一张账单,该查询可以正常工作,但问题是当客户有多个账单时。如果这些账单中的任何一个符合给定范围,它就会返回该账单。我只想检查最新的记录,如果该记录符合范围条件,则退回帐单。
编辑 2:
感谢@Caddy DZ
的asnwer,我设法得到了想要的结果。我只是更改了条件以监视在给定日期之前没有创建账单的客户。查询范围:
public function scopeNoActiveBill($query)
return $query->where('created_at', '>=', Carbon::create(2019, 9, 1));
控制器:
$clients = $clients->whereDoesntHave('bill')
->orWhereDoesntHave('bill', function ($query) use ($activeSchoolYear)
$query->noActiveBill();
);
【问题讨论】:
目前您只过滤clients
而不是bills
,为什么您希望只收到一张账单?你从哪里收到多张账单?当你打电话给$client->bills
?您可以使用$client->bills()->latest()->first();
获取客户的最新账单。
我试图从用户那里获得相关的账单。我不能只使用latest()->first()
,因为我预计会有大约 203 个结果。
【参考方案1】:
你可以使用 Eloquent whereDate()。
->whereDate('created_at', '<', Carbon::parse($activeSchoolYear->start));
【讨论】:
你能给出你要比较的确切日期字符串吗?【参考方案2】:您正在寻找的是这样的关系查询范围
$clients = App\Client::with(['bills' => function ($query)
$query->today();
])->get();
像这样将today()
范围添加到您的Bill
模型Bill.php
public function scopeToday($query)
// Change today by $activeSchoolYear if necessary
return $query->whereDate('created_at', '<', today());
假设Client
中的hasMany
关系
public function bills()
return $this->hasMany(Bill::class);
像这样播种的数据DatabaseSeeder.php
// Will be returned because whereDoesntHave('bills')
$clientWithoutBills = Client::create([]);
$client = Client::create([]);
$client->bills()->createMany([
[
'name' => 'test',
'created_at' => Carbon\Carbon::yesterday()
],
[
// Will not be returned because created today (not < today)
'name' => 'test1'
],
[
// Will not be returned because created tomorrow
'name' => 'test2',
'created_at' => Carbon\Carbon::tomorrow()
]
]);
Results
[
"id": 1,
"created_at": "2019-09-09 16:20:24",
"updated_at": "2019-09-09 16:20:24",
"bills": []
,
"id": 2,
"created_at": "2019-09-09 16:20:24",
"updated_at": "2019-09-09 16:20:24",
"bills": [
"id": 1,
"name": "test",
"client_id": 2,
"created_at": "2019-09-08 00:00:00",
"updated_at": "2019-09-09 16:20:24"
]
]
希望对你有帮助
【讨论】:
感谢您的详尽回复。我试着用你的罐头稍作修改,但我仍然收到一些不在规定范围内的客户账单。我将尝试使用您的解决方案,如果设法获得所需的结果,我会告诉您。 您可以编辑您的问题并添加您期望的结果示例吗?很难猜出你真正想要什么 对不起,我花了这么长时间才回复。我只想在 bills 表中的最后一行使用 where 子句。如果该行符合给定条件,则返回它,否则不返回任何内容。就我而言,如果我有 4 行,而第一行不符合条件,它仍然会返回该账单,因为其他 3 行符合给定条件。我稍微编辑了我的问题 更新:设法做到了,但我稍微改变了逻辑。我在查询范围内使用了whereDoesntHave
函数,以查看在给定日期之后创建的账单。将您的答案标记为已接受,因为它帮助我解决了这个问题。再次感谢。
很高兴它有帮助!以上是关于Laravel 雄辩查询的高级 where的主要内容,如果未能解决你的问题,请参考以下文章