我有一个系统,可以批准许多项目,并且可以在每个项目上看到批准的历史记录。一个例子是用户的里程碑,可以批准或拒绝。我的数据库中的表格如下:
+-----------------+------------------+
| Approvals |
+-----------------+------------------+
| Field | Type |
+-----------------+------------------+
| id | int(10) unsigned |
| approved | tinyint(1) |
| reason | text |
| approvable_id | varchar(191) |
| approvable_type | varchar(191) |
| created_at | timestamp |
| updated_at | timestamp |
+-----------------+------------------+
+----------------------+---------------------------------------+
| Milestones |
+----------------------+---------------------------------------+
| Field | Type |
+----------------------+---------------------------------------+
| id | int(10) unsigned |
| name | varchar(191) |
| created_at | timestamp |
| updated_at | timestamp |
+----------------------+---------------------------------------+
我希望能够获取接受最后批准的所有里程碑。例如,里程碑可能先前已被接受,但后来拒绝,在这种情况下,此里程碑不应出现在已接受的查询中,因为它已被拒绝。
我如何才能获取接受最新批准的里程碑?到目前为止,我尝试过的方法是创建一个exist
子查询,用于检查里程碑是否具有批准,即被接受。但是,这也取得了已被接受并随后被拒绝的结果:
SELECT * FROM `milestones`
WHERE EXISTS (
SELECT * FROM `approvals`
WHERE `milestones`.`id` = `approvals`.`approvable_id`
AND `approvals`.`approvable_type` = 'App\Models\Milestone'
AND `created_at` = (
SELECT MAX(created_at) FROM `approvals` AS `sub`
WHERE sub.approvable_id = approvals.approvable_id
AND sub.`approvable_type` = `approvals`.`approvable_type`
AND `sub`.`id` IN (
SELECT `id` FROM `approvals`
WHERE `approved` = 1
)
)
) AND `milestones`.`deleted_at` IS NULL
是否有可能获得接受最新批准的所有里程碑?或者这是否必须在应用程序级别完成?
答案 0 :(得分:1)
由于您使用Laravel对此进行了标记,并且您已经设置了可变形关系,即使您正在编写纯SQL,我也会向您展示Laravel(Eloquent)方式。 < / p>
如果我正确理解你,使用Laravel's Polymorphic Relationships我认为这应该有效:
<强> Approval.php 强>
BinaryFormatter
<强> Milestone.php 强>
<?php
namespace App\Models;
use App\Models\Milestone;
use Illuminate\Database\Eloquent\Model;
class Approval extends Model
{
public function approvable()
{
return $this->morphTo();
}
}
然后以最近的批准获得所有里程碑:
<?php
namespace App\Models;
use App\Models\Approval;
use Illuminate\Database\Eloquent\Model;
class Milestone extends Model
{
/**
* All approvals
*
* @return MorphMany
*/
public function approvals()
{
return $this->morphMany(Approval::class, 'approvable');
}
/**
* The most recent "approved" approval
*
* @return MorphMany
*/
public function lastestApproval()
{
return $this->morphMany(Approval::class, 'approvable')->where('approved', 1)->latest()->limit(1);
}
}
这是DB结构的样子(应该与你的相同):
答案 1 :(得分:1)
这应该做的工作
select m.*,a.*
from milestones m
join approvals a on m.id = a.approvable_id
join (
select approvable_id, max(created_at) created_at
from approvals
group by approvable_id
) aa on a.approvable_id = aa.approvable_id
and a.created_at = aa.created_at
where a.approved = 1 /* other filters in query */
首先,它会将每个里程碑与来自审批表的最新记录一起加入,然后在where子句中过滤掉批准的最新批准= 1
答案 2 :(得分:0)
正如tptcat指出的那样,这个问题被标记为Laravel问题。所以使用M Khalid Junaid's回答我将其转换为Eloquent语法(或尽我所能)并得到以下内容:
public function scopeApproved($query, $accepted=true)
{
return $query->select('milestones.*', 'approvals.*')
->join('approvals', 'milestones.id', '=', 'approvals.approvable_id')
->join(\DB::raw(
'(SELECT approvable_id, MAX(created_at) created_at
FROM approvals
GROUP BY approvable_id) aa' ), function($join)
{
$join->on('approvals.approvable_id', '=', 'aa.approvable_id')
->on('approvals.created_at', '=', 'aa.created_at');
})->where('approvals.approved', $accepted);
}