mysql 筛选器具有One of Many查询

ufj5ltwl  于 5个月前  发布在  Mysql
关注(0)|答案(2)|浏览(48)

我正在尝试使用Laravel的hasOne(Model::class)->ofMany('relationship'),但我也想额外过滤考虑的结果。
我的问题更详细一点:
我有这两个简化的表格,我在所见即所得风格的创作工具中使用:
文档:id (PK),...
文档修订表:id (PK),document_id (FK),revision_id,is_autosave,...
在修订表中,组合document_id, revision_id, is_autosave是唯一的,这意味着文档可以具有相同的revision_id,用于自动保存和手动保存的修订。
我正在尝试使用以下代码将最新手动保存的修订与文档模型相关联:

public function mainRevision() {
   return $this->hasOne(DocumentRevision::class)
      ->where('autosave', false)
      ->ofMany('revision_id', 'max');
}

字符串
我可以调用上面的代码,例如Documents::with('mainRevision')->where(...)->get()。目的是快速加载最新的手动修订版,并且只为所有匹配的文档行加载最新的手动修订版。
但是,这会生成以下查询:

select
    `document_revisions`.*
from
    `document_revisions` inner join (
        select
            max(`document_revisions`.`id`) as `id_aggregate`,
            min(`document_revisions`.`revision_id`) as `revision_id_aggregate`,
            `document_revisions`.`document_id`
        from
            `document_revisions`
                inner join (
                    select max(`document_revisions`.`revision_id`) as `revision_id_aggregate`,`document_revisions`.`document_id`
                    from `document_revisions` 
                    where `document_revisions`.`document_id` in (`<list of matched ids from the 1st query>`)
                group by
                    `document_revisions`.`document_id`
            ) as `mainVersion`
            on `mainVersion`.`revision_id_aggregate` = `document_revisions`.`revision_id` and `mainVersion`.`document_id` = `document_revisions`.`document_id`
        group by `document_revisions`.`document_id`) as `mainVersion` 
    on `mainVersion`.`id_aggregate` = `document_revisions`.`id`
        and `mainVersion`.`revision_id_aggregate` = `document_revisions`.`revision_id`
        and `mainVersion`.`document_id` = `document_revisions`.`document_id`
where
    `autosave` = 0


虽然我可以看到这里的意图,但有一个问题是,where autosave=0被添加到连接表之外。这会导致如果最新的revision_id碰巧只对应于一个autosave,那么它不会被拾取。
我希望理想的查询是这样的:

select
    `document_revisions`.*
from
    `document_revisions` inner join (
        select
            max(`document_revisions`.`id`) as `id_aggregate`,
            min(`document_revisions`.`revision_id`) as `revision_id_aggregate`,
            `document_revisions`.`document_id`
        from
            `document_revisions`
                inner join (
                    select max(`document_revisions`.`revision_id`) as `revision_id_aggregate`,`document_revisions`.`document_id`
                    from `document_revisions` 
                    where `autosave` = 0 --<<----------- change here
                     and `document_revisions`.`document_id` in (`<list of matched ids from the 1st query>`) 
                group by
                    `document_revisions`.`document_id`
            ) as `mainVersion`
            on `mainVersion`.`revision_id_aggregate` = `document_revisions`.`revision_id` and `mainVersion`.`document_id` = `document_revisions`.`document_id`
        group by `document_revisions`.`document_id`) as `mainVersion` 
    on `mainVersion`.`id_aggregate` = `document_revisions`.`id`
        and `mainVersion`.`revision_id_aggregate` = `document_revisions`.`revision_id`
        and `mainVersion`.`document_id` = `document_revisions`.`document_id`


有人知道这是否可能吗?

33qvvth1

33qvvth11#

根据文档,您可以通过将闭包作为第二个参数传递来向ofMany()查询添加条件。这也需要使用数组表示法在第一个参数中传递聚合列。示例如下:

public function mainRevision() {
    return $this->hasOne(DocumentRevision::class)
        ->ofMany([
            'revision_id' => 'max'
        ], function (Builder $query) {
            return $query->where('autosave', false);
        });
}

字符串
不相关,但Laravel也有另一种定义“众多之一”的方法,你可能更喜欢,通过将现有的hasMany()关系转换为hasOne()。这和你所拥有的没有区别,只是风格的偏好。假设你将hasMany()关系定义为documentRevisions(),你可以调用one()方法将其转换为hasOne()关系:

public function mainRevision() {
    return $this->documentRevisions()
        ->one()
        ->ofMany([
            'revision_id' => 'max'
        ], function (Builder $query) {
            return $query->where('autosave', false);
        });
}

qzwqbdag

qzwqbdag2#

尝试以下操作,在确定最新版本的子查询中应用autosave = 0条件。

public function mainRevision() {
    return $this->hasOne(DocumentRevision::class)
        ->selectRaw('document_revisions.*, max(document_revisions.revision_id) as max_revision_id')
        ->where('autosave', false)
        ->groupBy('document_revisions.document_id')
        ->orderBy('max_revision_id', 'desc');
}

字符串

相关问题