0

我正在使用 CakePHP 3.5.13 重建一个普通的 PHP/MySQL 应用程序。

原始应用程序中的一个查询需要在同一个表上构建一个JOIN条件,并通过使用单独的表别名来实现。查询如下 - 并给出了我们期望的正确结果:

SELECT DISTINCT(s.id) FROM substances s
JOIN display_substances AS dsUses
ON (s.id = dsUses.substance_id AND dsUses.display_id = 128 AND  (dsUses.value LIKE '%dye%') ) 
JOIN display_substances AS displays
ON (s.id = displays.substance_id AND displays.display_id NOT IN (1,2,3,4,6,128) AND  (displays.value LIKE '%bpr%'))

需要这样做的原因是因为查询正在搜索 2 个单独的用户输入项 - 在同一个表 ( display_substances) 中但针对不同的display_substances .display_id字段。就上面的查询而言,它意味着:

  • 搜索在"%dye%"哪里display_id = 128
  • 搜索不存在"%bpr%"的地方display_id 1,2,3,4,6 or 128

在 Cake 中,我在一个处理搜索功能的控制器中这样写:

$query = $Substances->find()->select(['id' => 'Substances.id'])->distinct();

// Search for "dye"
$query = $query->matching('DisplaySubstances', function ($q) use ($uses_summary) {
return $q->where([
        'DisplaySubstances.value LIKE' => '%dye%', // "dye" is dynamic and comes from $uses_summary
        'DisplaySubstances.display_id' => 128
    ]);
});

// Search for "bpr"
$query = $query->matching('DisplaySubstances', function ($q) use ($regulatory_information) {
    return $q->where([
            'DisplaySubstances.value LIKE' => '%bpr%', // "bpr" is dynamic and comes from $regulatory_information
            'DisplaySubstances.display_id NOT IN' => [1,2,3,4,6,128]
        ]);
 });

这会产生错误的 SQL,因为当我调试时$query->sql();它给出了不同的JOIN条件:

INNER JOIN display_substances DisplaySubstances ON 
(
    DisplaySubstances.value like "%dye%" AND DisplaySubstances.display_id = 128 
    AND DisplaySubstances.value like "%bpr%" 
    AND DisplaySubstances.display_id not in (1,2,3,4,6,128) 
    AND Substances.id = (DisplaySubstances.substance_id)
)

我不确定如何重写此查询,以便它将两个搜索输入中的JOIN每一个都视为一个条件,就像原始查询一样。

我注意到的主要事情是原始查询对同一个表(AS dsUsesAS displays)有不同的别名。我不确定这是否相关?

我正在尝试使用 ORM 而不是手动编写 SQL,因此更愿意知道如何使用它来执行此操作。

4

1 回答 1

2

无法matching()调用指定自定义别名,目前同一关联上的多个matching()调用将合并条件,如您生成的 SQL 片段中所示。

现在,您必须使用不同的别名创建其他关联(即除了DisplaySubstances您的类中的关联之外):SubstancesTable

$this->hasMany('DsUses', [
    'className' => 'DisplaySubstances'
]);
$this->hasMany('Displays', [
    'className' => 'DisplaySubstances'
]);

然后您可以在其上匹配:

$query->matching('DsUses', function ($q) use ($regulatory_information) {
    return $q->where([
        'DsUses.value LIKE' => '%dye%',
        'DsUses.display_id' => 128
    ]);
});

$query->matching('Displays', function ($q) use ($regulatory_information) {
    return $q->where([
        'Displays.value LIKE' => '%bpr%',
        'Displays.display_id NOT IN' => [1, 2, 3, 4, 6, 128]
    ]);
});

或手动构建连接,例如使用innerJoin()

$query->innerJoin(
    [
        'DsUses' => 'display_substances'
    ],
    [
        'Substances.id' => new \Cake\Database\Expression\IdentifierExpression('DsUses.substance_id'),
        'DsUses.display_id' => 128,
        'DsUses.value LIKE' => '%dye%'
    ],
    [
        'DsUses.display_id' => 'integer',
        'DsUses.value' => 'string'
    ]
);

$query->innerJoin(
    [
        'Displays' => 'display_substances'
    ],
    [
        'Substances.id' => new \Cake\Database\Expression\IdentifierExpression('Displays.substance_id'),
        'Displays.display_id NOT IN' => [1, 2, 3, 4, 6, 128],
        'Displays.value LIKE' => '%bpr%'
    ],
    [
        'Displays.display_id' => 'integer',
        'Displays.value' => 'string'
    ]
);

也可以看看

于 2019-02-18T15:33:23.357 回答