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

CakePHP 3-如何为同一个字段定义多个条件?,cakephp,query-builder,cakephp-3.x,Cakephp,Query Builder,Cakephp 3.x,我正在使用CakePHP3.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 (14

我正在使用CakePHP3.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());
上面的查询工作正常,但不完整:它将给出所有结果,但不考虑(在普通SQL中)包含(147)中的
fs.filter\u id的行

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

我尝试了以下几点:

// 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%

我读过这本书,这是我如何设法完成工作的第一部分。然而,该示例中的查询可以说不那么复杂,并且不能满足我在这里的需要


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

您的问题基本上是需要多次使用相同的标识符,这在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
])
另见


我理解,如果组中可能出现相同的
物质id
,则不能将
中的
中的
组合在一起,但是
中的前两个
应该是可合并的,因为它们是通过
?@ndm组合在一起的。如果您尝试这样做,将会产生非常不同的结果。这就是我添加“重要”注释的原因。例如,如果我在原始SQL中执行,其中fs.filter_id在(147,47,93))
(全部在一个条件下),它将生成6000多行。然而,当它们分开时,它产生2(
fs.filter\u id在(147)
中,然后是
fs.filter\u id在(47,93)
)。不幸的是,我不能提供数据库。但是以这种方式运行查询时会有一些细微的差别。是的,对不起,我有点分心,当然这是不同的,因为
中的
基本上是
的列表……没问题,我总是很感谢任何帮助。我想我的问题是,这样的条件是否可以在ORM中编写,或者我是否最好走“在蛋糕中编写您自己的SQL”的道路?这是一个遗憾,因为ORM使编写大部分查询变得非常简单,我不想编写构造SQL所有这些部分的东西。这个应用程序允许用户选择不同的过滤器,所以也有不同的选择,但现在我最感兴趣的是知道这是否可以通过ORM实现。这真的很好。用于构造此类语句的普通PHP要复杂得多。我很高兴ORM能够做到这一点。