目标
我正在尝试返回所有features
以及所有关联的(如果有的话)features_user_types
,其中user_type_id =?。
例如,我有2 features
。只要user_type_id = 2,我希望两者都与所有关联的features_user_types
一起返回。如果没有匹配的feature_user_type
,那么无论如何都应该返回feature
。
预期成果
示例输出:WHERE user_type_id = 2
"features": [
{
"id": 1,
"features_user_types": [
{
"id": 79,
"feature_id": 1,
"user_type_id": 2,
"position": 3
}
]
},
{
"id": 2,
"features_user_types": []
}
]
实际结果
但是,目前它返回所有相关的features_user_types,尽管它们的id不等于2。
$ query-> toArray()输出:
"features": [
{
"id": 1,
"features_user_types": [
{
"id": 79,
"feature_id": 1,
"user_type_id": 2,
"position": 3
}
]
},
{
"id": 2,
"features_user_types": [
{
"id": 72,
"feature_id": 2,
"user_type_id": 1,
"position": 9
}
]
}
]
数据结构
表格结构:
features
-id
features_user_types
-id
-feature_id
-user_type_id
-position
user_types
-id
CakePHP关联定义:
FeaturesTable:
$this->belongsToMany('UserTypes', [
'foreignKey' => 'feature_id',
'targetForeignKey' => 'user_type_id',
'joinTable' => 'features_user_types'
]);
$this->hasMany('FeaturesUserTypes', [
'foreignKey' => 'feature_id'
]);
UserTypesTable:
$this->belongsToMany('Features', [
'foreignKey' => 'user_type_id',
'targetForeignKey' => 'feature_id',
'joinTable' => 'features_user_types'
]);
$this->hasMany('FeaturesUserTypes', [
'className' => 'FeaturesUserTypes',
'foreignKey' => 'user_type_id'
]);
FeaturesUserTypesTable:
$this->belongsTo('Features', [
'foreignKey' => 'feature_id',
'joinType' => 'INNER'
]);
$this->belongsTo('UserTypes', [
'foreignKey' => 'user_type_id',
'joinType' => 'INNER'
]);
QUERY OBJECT
我的cakephp应用程序中有一个查询构建器,它根据$query->sql()
创建以下sql:
SELECT DISTINCT
Features.id AS `Features__id`,
Features.created AS `Features__created`,
Features.modified AS `Features__modified`,
Features.name AS `Features__name`,
Features.description AS `Features__description`
FROM features Features
LEFT JOIN features_user_types FeaturesUserTypes
ON (FeaturesUserTypes.user_type_id = 2
AND Features.id = (FeaturesUserTypes.feature_id))
的MySQL
但是,如果我将其直接复制并粘贴到MySQL中,我会得到我期望的结果,只返回与features
匹配的所有featurs_user_types
。
实际查询:
SELECT DISTINCT *
FROM features Features
LEFT JOIN features_user_types FeaturesUserTypes
ON (FeaturesUserTypes.user_type_id = 2
AND Features.id = (FeaturesUserTypes.feature_id))
MySQL输出:
----------------------------------------------------------------------------
|ID (feature id)|ID (feature_user_type_id)|feature_id|user_type_id|position|
| 1 | 79 | 1 | 2 | 3 |
| 2 | NULL | NULL | NULL | NULL |
----------------------------------------------------------------------------
CODE
AppController的:
我的AppController非常通用,但是可以从URL中获取参数来生成和执行sql查询。它是一个相当大的文件,所以我用调试器完成了它并记录了$ query被更改并填充变量的任何行,以使其更加明显。
$key = 'FeaturesUserTypes.user_type_id';
$value = 2;
$model = $this->loadModel();
$query = $model->find('all', ['fields' => $this->getFields()]);
$query->contain(['FeaturesUserTypes']);
$query->leftJoinWith('FeaturesUserTypes', function($q) use ($key, $value) {
return $q->where([$key => $value]);
});
$query->distinct();
$results = $query->toArray();
对可能发生的事情有任何想法?我正在运行CakePHP 3和PHP 5.6.10。谢谢!
答案 0 :(得分:3)
与hasOne
和belongsTo
关联不同,它们在主查询中使用连接,除非另外明确配置,hasMany
和belongsToMany
关联数据始终在单独检索查询。
请注意,sql()
将始终只返回主查询,而不是用于预先加载关联的可能的其他查询!如果您需要了解其他查询,请查看DebugKits SQL日志面板。那么这意味着,您手动测试的查询不是ORM实际用于检索关联数据的查询。
您正在寻找的是传递包含的条件,即删除leftJoinWith()
(除非您需要主查询中的关联数据以进行进一步的SQL级别操作),并将条件回调附加到{代替{1}}遏制:
FeaturesUserTypes
对于读取此内容的任何人,请确保$query->contain([
'FeaturesUserTypes' => function($q) use ($key, $value) {
return $q->where([$key => $value]);
}
]);
不包含用户输入,否则这将是SQL注入漏洞!
另见
答案 1 :(得分:0)
在ON
子句中进行过滤通常 错误:
FROM a
JOIN b ON b.x = 2 AND a.z=b.z
将过滤移至WHERE
:
FROM a
JOIN b ON a.z=b.z
WHERE b.x = 2
另外,请不要使用LEFT
,除非您想要“右”表中“缺失”行的空值。
我不知道您的数据,但似乎DISTINCT
不合适。