CakePHP 3 - 如何为同一个字段定义多个条件?

时间:2018-03-21 16:02:43

标签: cakephp query-builder cakephp-3.x

我正在使用CakePHP 3.5.13中的应用程序。它与传统"数据库 - 即根据CakePHP命名约定未编写的数据库。尽管如此,我还是将它烘焙并生成了表格和实体文件。

我在使用ORM构建SQL查询时遇到问题。

查询 - 在纯SQL中 - 看起来像这样:

SELECT s.id FROM substances s WHERE s.id 
IN
    (SELECT fs.substance_id FROM filters_substances fs WHERE fs.filter_id IN (147))
AND s.id IN 
    (SELECT fs.substance_id FROM filters_substances fs WHERE fs.filter_id IN (47,93))
AND s.id NOT IN
    (SELECT fs.substance_id FROM filters_substances fs WHERE fs.filter_id IN (148,354))

我设法使用ORM编写以下内容:

$subquery_in = $FiltersSubstances
    ->find()
    ->select(['FiltersSubstances.substance_id'])
    ->where(['FiltersSubstances.filter_id IN' => [47,93]]);

$subquery_not_in = $FiltersSubstances
    ->find()
    ->select(['FiltersSubstances.substance_id'])
    ->where(['FiltersSubstances.filter_id IN' => [354]]);

$Substances = TableRegistry::get('Substances');

$query = $Substances
    ->find()
    ->where([
        'Substances.id IN' => $subquery_in,
        'Substances.id NOT IN ' => $subquery_not_in
    ]);

debug($query);
debug($query->all());

以上查询工作正常但不完整:它会给我所有结果,但不会考虑包含fs.filter_id IN (147)的行(在纯SQL中)。

我遇到的问题是我不知道如何生成多个AND IN子查询。

我尝试过以下方法:

// Same as PHP given previously, plus:

$subquery_in2 = $FiltersSubstances
    ->find()
    ->select(['FiltersSubstances.substance_id'])
    ->where(['FiltersSubstances.filter_id IN' => [147]]);

// Modified $query:

$query = $Substances
    ->find()
    ->where([
        'Substances.id IN' => [$subquery_in, $subquery_in2],
        'Substances.id NOT IN ' => $subquery_not_in]
    );

// Also tried:

$query = $Substances
    ->find()
    ->where([
        'Substances.id IN' => $subquery_in,
        'Substances.id IN' => $subquery_in2,
        'Substances.id NOT IN ' => $subquery_not_in
    ]);

以上尝试不起作用 - SQL错误。

请问是否有人可以建议在ORM中构建此查询是否可行?如何?

我考虑过去"原始SQL"手写的路线。这似乎是一个很大的耻辱,因为ORM正在做我需要的95%。

我已阅读Cakephp 3 NOT IN query,这就是我如何设法完成工作所需的第一部分。但是,该示例中的查询可能不那么复杂,并且不能满足我的需求。

重要:原始SQL会生成正确的结果。我知道有些人可能会说,为什么不将所有IN ID分组到一个查询中。但是,这会产生非常不同 - 而且不正确 - 的结果。 IN... AND IN在这里非常重要。我知道查询很好,它是如何在Cake的我感兴趣的ORM中编写的。

1 个答案:

答案 0 :(得分:3)

您的问题基本上是您需要多次使用相同的标识符,这在PHP数组中是无效的。

您可以通过嵌套条件来解决此问题:

->where([
    ['Substances.id IN' => $subquery_in],
    ['Substances.id IN' => $subquery_in2],
    'Substances.id NOT IN ' => $subquery_not_in
])

发出多个where()来电:

->where(['Substances.id IN' => $subquery_in])
->where(['Substances.id IN' => $subquery_in2])
->where(['Substances.id NOT IN' => $subquery_not_in])

或使用表达式:

->where(function (\Cake\Database\Expression\QueryExpression $exp) use (
    $subquery_in,
    $subquery_in2,
    $subquery_not_in
) {
    return $exp
        ->in('Substances.id', $subquery_in)
        ->in('Substances.id', $subquery_in2)
        ->notIn('Substances.id', $subquery_not_in);
})

也可以将表达式与常规数组语法混合使用:

$inExpressions = $query
    ->newExpr()
    ->in('Substances.id', $subquery_in)
    ->in('Substances.id', $subquery_in2);

// ...

->where([
    $inExpressions,
    'Substances.id NOT IN ' => $subquery_not_in
])

另见