기본 범위에서 INNER JOIN을 사용하면 INNER JOIN이 잘못된 테이블에 적용됩니다. 나는 Task
, Project
, ProjectUser
및 User
의 4 가지 모델이 있습니다. 그들의 구조, 관계 및 기본 범위는 아래에서 볼 수 있습니다.추가 조인 대신 중첩 SELECT 사용
프로젝트는 사용자가 ProjectUser 링크를 통해 프로젝트에 할당 된 경우에만 볼 수 있습니다. 각 프로젝트에는 많은 작업이 있습니다. 작업이 상위 프로젝트에 BELONGS_TO 관계가 있습니다. 상위 프로젝트가 해당 사용자에게 표시되는 경우에만 사용자가 볼 수 있습니다.
내가 쿼리 할 때 :
$tasks = Task::model()->withoutChildren()->findAll();
아무 것도 반환하지 않습니다.
내 모델 : (크게이 게시물에 대한 간체)
class Task extends CActiveRecord {
/*
Columns:
id
parent_task_id
project_id
*/
public function relations() {
return array(
'project' => array(self::BELONGS_TO, 'Project', 'project_id'),
'subTasks' => array(self::HAS_MANY, 'Task', 'parent_task_id', 'alias' => "Task_subTasks"),
'parentTask' => array(self::BELONGS_TO, 'Task', 'parent_task_id'),
);
}
public function scopes() {
$t = $this->tableAlias;
return array(
'withoutChildren'=>array(
'with' => array("subTasks"),
'select' => "COUNT(Task_subTasks.id) AS subTaskCount",
'group' => "$t.id",
'having' => "subTaskCount = 0",
)
);
}
public function defaultScope() {
$t = $this->getTableAlias(false, false);
return array(
'with' => array(
"project" => array(
'select' => false,
'alias' => "Task_def_". $t,
'joinType' => "INNER JOIN"
)
)
);
}
}
class Project extends CActiveRecord {
/*
Columns:
id
*/
public function relations()
{
return array(
'projectUsers' => array(self::HAS_MANY, 'ProjectUser', 'project_id'),
'tasks' => array(self::HAS_MANY, 'Task', 'project_id'),
'users' => array(self::MANY_MANY, 'User', 'project_user(project_id, user_id)'),
);
}
public function defaultScope() {
$t = $this->getTableAlias(false, false);
return array(
'with' => array(
'projectUsers' => array(
'joinType' => "INNER JOIN",
'alias' => "{$t}_pu",
'on' => "{$t}_pu.user_id=". User::current()->id
)
)
);
}
}
class ProjectUser extends CActiveRecord {
/*
Columns:
id
project_id
user_id
*/
public function relations()
{
return array(
'project' => array(self::BELONGS_TO, 'Project', 'project_id'),
'user' => array(self::BELONGS_TO, 'User', 'user_id'),
);
}
}
class User extends CActiveRecord {
}
작동하지 않는 이유를 나는 이해한다. 쿼리 YII가 생성이다 : (다시 크게 단순화)
SELECT COUNT(Task_subTasks.id) AS subTaskCount, (all the other field...) FROM `task` `t`
INNER JOIN `project` `Task_def_t` ON (`t`.`project_id`=`Task_def_t`.`id`) AND
INNER JOIN `project_user` `Task_def_t_pu`
ON (`Task_def_t_pu`.`project_id`=`Task_def_t`.`id`) AND
(Task_def_t_pu.user_id=6)
LEFT OUTER JOIN
`task` `Task_subTasks` ON (`Task_subTasks`.`parent_task_id`=`t`.`id`) AND
INNER JOIN `project`
`Task_def_Task_subTasks` ON
(`Task_subTasks`.`project_id`=`Task_def_Task_subTasks`.`id`) AND
INNER JOIN `project_user`
`Task_def_Task_subTasks_pu` ON
(`Task_def_Task_subTasks_pu`.`project_id`=`Task_def_Task_subTasks`.`id`)
AND (Task_def_Task_subTasks_pu.user_id=6)
GROUP BY t.id
HAVING (subTaskCount = 0)
을이 경우 4와 5는 'task' 't'
테이블에 적용 합류했다. 어떤 일이 있어서는 안된다. 이제 원본 쿼리를 더 많이 제한하므로 쿼리가 0 행을 반환합니다.
그러나 4 번째 및 5 번째 JOIN은 LEFT OUTER JOIN 'task' 'Task_subTasks'
에 적용되어야합니다 ('적용'은 올바른 용어 임). 어쨌든, 이것은 Yii가 생성하기를 기대하는 것입니다 :
SELECT (all the other field...) FROM `task` `t`
INNER JOIN `project` `Task_def_t` ON (`t`.`project_id`=`Task_def_t`.`id`) AND
INNER JOIN `project_user` `Task_def_t_pu`
ON (`Task_def_t_pu`.`project_id`=`Task_def_t`.`id`) AND
(Task_def_t_pu.user_id=6)
WHERE (
SELECT COUNT(Task_subTasks.id) FROM `task` `Task_subTasks`
INNER JOIN `project`
`Task_def_Task_subTasks` ON
(`Task_subTasks`.`project_id`=`Task_def_Task_subTasks`.`id`) AND
INNER JOIN `project_user`
`Task_def_Task_subTasks_pu` ON
(`Task_def_Task_subTasks_pu`.`project_id`=`Task_def_Task_subTasks`.`id`)
AND (Task_def_Task_subTasks_pu.user_id=6)
WHERE (`Task_subTasks`.`parent_task_id`=`t`.`id`)
) = 0
GROUP BY t.id
나는이 간단한 쿼리를 테스트하지 않고 편집했습니다. 그러나 원본 쿼리 (방대한 쿼리)를 같은 방식으로 변환하고 이제는 작동합니다!
내 질문 : Yii가 같은 테이블에 모든 조인을 추가하는 대신 중첩 된 SELECT를 사용하여 쿼리하도록 지시하는 방법은 무엇입니까?
$tasks = Task::model()->findBySql('your_sql_here');
을하고 정답을 즐길 수 : 유사한 상황에서
'WHERE (SELECT) = 0' 행에 뭔가있는 것이 있으면 실제로는 존재하지 않는 (...) 상태가되어 최적화 프로그램이 더 잘 최적화됩니다. 죄송 합니다만, 나는 당신을 도울 수 없어요. –