cakephp4中的联合请求和分页

ybzsozfc  于 2023-02-04  发布在  PHP
关注(0)|答案(1)|浏览(146)

我做了两个请求,第一个请求提供了2419个结果,我把结果存储在$requestFirst中,第二个请求提供了1个结果,我把结果存储在$requestTwo中,我做了一个并集:

$requestTot = $requestFirst->union($requestTwo);

$requestTot的总数是2420个结果,所以到目前为止一切正常。

$request = $this->paginate($requestTot);
$this->set(compact('request'));

这里我不明白,在分页的每一页上我都找到了$requestTwo的结果。而且分页显示了我:

Page 121 of 121, showing 20 record(s) out of 2,420 total

这是正确的结果数,只是当我将每页的结果数乘以页数时,得到2540。这是结果总数加上每页1。
有人能解释吗?

bwitn5fc

bwitn5fc1#

Debug Kit的SQL面板中检查生成的SQL,您应该看到LIMIT AND OFFSET子句是在第一个查询上设置的,而不是作为全局子句附加的,这样它们会影响联合查询。
它看起来像这样:

(SELECT id, title FROM a LIMIT 20 OFFSET 0)
UNION
(SELECT id, title FROM b)

因此,分页将只应用于$requestFirst查询,而$requestTwo查询每次都将在它上面进行并集化,因此您将在每个页面上看到它的结果。
解决此当前限制的方法是将联合查询用作从中提取结果的子查询或公用表表达式。要使此方法正常工作,您需要确保选择的联合查询字段没有别名!这可以通过使用Table::subquery()来实现:

$requestFirst = $this->TableA
    ->subquery()
    ->select(['a', 'b'])
    // ...

$requestTwo = $this->TableB
    ->subquery()
    ->select(['c', 'd'])
    // ...

或者显式选择别名等于列名的字段:

$requestFirst = $this->TableA
    ->find()
    ->select(['a' => 'a', 'b' => 'b'])
    // ...

$requestTwo = $this->TableB
    ->find()
    ->select(['c' => 'c', 'd' => 'd'])
    // ...

然后,您可以安全地将这些联合查询用作子查询:

$union = $requestFirst->union($requestTwo);

$wrapper = $this->TableA
    ->find()
    ->from([$this->TableA->getAlias() => $union]);

$request = $this->paginate($wrapper);

或作为公用表表达式(如果DBMS支持它们):

$union = $requestFirst->union($requestTwo);

$wrapper = $this->TableA
    ->find()
    ->with(function (\Cake\Database\Expression\CommonTableExpression $cte) use ($union) {
        return $cte
            ->name('union_source')
            ->field(['a', 'b'])
            ->query($union)
    })
    ->select(['a', 'b'])
    ->from([$this->TableA->getAlias() => 'union_source']);

$request = $this->paginate($wrapper);

相关问题