CakePHP 3 - 在分离 JOIN 条件时使用不同的 table 别名
CakePHP 3 - use different table aliases when separating JOIN conditions
我正在使用 CakePHP 3.5.13 重建普通 PHP/MySQL 应用程序。
原始应用程序中的一个查询需要在相同的 table 上构建 JOIN
条件,并通过使用单独的 table 别名来实现。查询如下 - 并给出了我们期望的正确结果:
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 个单独的用户输入项 - 在相同的 table(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
条件。
我注意到的主要事情是原始查询具有相同 table(AS dsUses
和 AS displays
)的单独别名。我不确定这是否相关?
我正在尝试使用 ORM 而不是手动编写 SQL,所以我更想知道如何使用它来完成此操作。
可以 not yet 为 matching()
调用指定自定义别名,目前对同一关联的多个 matching()
调用将合并条件,如您生成的 SQL 片段。
现在您必须使用不同的别名创建额外的关联(即在您的 SubstancesTable
class 中添加您的 DisplaySubstances
关联):
$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'
]
);
另见
我正在使用 CakePHP 3.5.13 重建普通 PHP/MySQL 应用程序。
原始应用程序中的一个查询需要在相同的 table 上构建 JOIN
条件,并通过使用单独的 table 别名来实现。查询如下 - 并给出了我们期望的正确结果:
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 个单独的用户输入项 - 在相同的 table(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
条件。
我注意到的主要事情是原始查询具有相同 table(AS dsUses
和 AS displays
)的单独别名。我不确定这是否相关?
我正在尝试使用 ORM 而不是手动编写 SQL,所以我更想知道如何使用它来完成此操作。
可以 not yet 为 matching()
调用指定自定义别名,目前对同一关联的多个 matching()
调用将合并条件,如您生成的 SQL 片段。
现在您必须使用不同的别名创建额外的关联(即在您的 SubstancesTable
class 中添加您的 DisplaySubstances
关联):
$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'
]
);
另见