使用内连接和左连接时 Yii2 关系重复
Yii2 relation duplicate when use inner join and jeft join
有3个模型之间有关系。
范例
class A extends ActiveRecord
{
public static function tableName(){
return 'tbl_a';
}
public function getB()
{
return $this->hasOne(B::className(), ['column' => 'column']);
}
}
class B extends ActiveRecord
{
public static function tableName(){
return 'tbl_b';
}
public function getC()
{
return $this->hasOne(C::className(), ['column' => 'column']);
}
}
我有下一个代码:
$result = A::find()->joinWith('b')->where('');
if () {
A->joinWith('b.c')->where('');
}
$result->createCommand()->rawSql;
接下来的结果是 sql:
select * from tbl_a left join tbl_b on ... join tbl_b on ... join tbl_c on ... where ...
如您所见,sql 查询重复 table 关系 'tbl_b'。你知道为什么吗?
更新
好的,我更详细地研究了我的问题。
Table 如果使用不同的 JOIN 类型,连接会重复。
下一个原始模型:
class Myuser extends ActiveRecord
{
public static function tableName(){
return 'myuser';
}
public function getProfile()
{
return $this->hasOne(Profile::className(), ['user_id' => 'id']);
}
}
class Profile extends \yii\db\ActiveRecord {
public static function tableName(){
return 'profile';
}
public function getCity()
{
return $this->hasOne(City::className(), ['id'=>'city_id']);
}
}
执行代码:
$get_city = 1;
$u = Myuser::find()->joinWith('profile', 0, 'INNER JOIN');
if ($get_city) {
$u->joinWith('profile.city');
}
echo $u->createCommand()->rawSql;
结果:
SELECT `myuser`.* FROM `myuser`
INNER JOIN `profile` ON `myuser`.`id` = `profile`.`user_id`
LEFT JOIN `profile` ON `myuser`.`id` = `profile`.`user_id`
LEFT JOIN `city` ON `profile`.`city_id` = `city`.`id`
如果我需要获得唯一的 table 'profile' 并从 table 'city' 添加字段,我该如何避免重复。如果 table 'city' 中没有字段,则值应为 'null'.
我想这是框架中的一个错误(或功能)。当您使用关系 profile.city
框架看不到 inner join
已经加入的关系...我假设如果您使用 left join
作为第一个关系,一切都会正常。
在您的情况下,请尝试使用 leftJoin()
并指定要加入的 table 名称:
$get_city = 1;
$u = Myuser::find()->innerJoinWith('profile');
if ($get_city) {
$u->leftJoin('city', 'profile.city_id = city.id');
}
echo $u->createCommand()->rawSql;
这是因为您对这两个联接使用了不同的联接类型。 joinWith('profile', false, 'INNER JOIN')
和 joinWith('profile')
将生成不同的 JOIN
(joinWith()
默认使用 LEFT JOIN
作为连接类型),因此您有 2 个连接查询。如果您想避免重复,您可以对这两个 joinWith()
调用使用相同的设置:
$get_city = 1;
$u = Myuser::find()->joinWith('profile', false, 'INNER JOIN');
if ($get_city) {
$u->joinWith('profile.city', false, 'INNER JOIN');
}
echo $u->createCommand()->rawSql;
结果:
SELECT `myuser`.* FROM `myuser` INNER JOIN `profile` ON `myuser`.`id` = `profile`.`user_id` INNER JOIN `city` ON `profile`.`city_id` = `city`.`id`
如果你想结合INNER JOIN
和LEFT JOIN
,你可以使用扩展语法:
$get_city = 1;
if ($get_city) {
$u = Myuser::find()->joinWith(
[
'profile' => function (ActiveQuery $query) {
$query->joinWith('city');
},
],
false,
'INNER JOIN'
);
} else {
$u = Myuser::find()->joinWith('profile', false, 'INNER JOIN');
}
echo $u->createCommand()->rawSql;
结果:
SELECT `myuser`.* FROM `myuser` INNER JOIN `profile` ON `myuser`.`id` = `profile`.`user_id` LEFT JOIN `city` ON `profile`.`city_id` = `city`.`id`
如果您与同一个 table 有多个关系,您应该为它们使用不同的别名。如果不是,Yii 将加入 table,导致错误或重复
有3个模型之间有关系。 范例
class A extends ActiveRecord
{
public static function tableName(){
return 'tbl_a';
}
public function getB()
{
return $this->hasOne(B::className(), ['column' => 'column']);
}
}
class B extends ActiveRecord
{
public static function tableName(){
return 'tbl_b';
}
public function getC()
{
return $this->hasOne(C::className(), ['column' => 'column']);
}
}
我有下一个代码:
$result = A::find()->joinWith('b')->where('');
if () {
A->joinWith('b.c')->where('');
}
$result->createCommand()->rawSql;
接下来的结果是 sql:
select * from tbl_a left join tbl_b on ... join tbl_b on ... join tbl_c on ... where ...
如您所见,sql 查询重复 table 关系 'tbl_b'。你知道为什么吗?
更新
好的,我更详细地研究了我的问题。 Table 如果使用不同的 JOIN 类型,连接会重复。 下一个原始模型:
class Myuser extends ActiveRecord
{
public static function tableName(){
return 'myuser';
}
public function getProfile()
{
return $this->hasOne(Profile::className(), ['user_id' => 'id']);
}
}
class Profile extends \yii\db\ActiveRecord {
public static function tableName(){
return 'profile';
}
public function getCity()
{
return $this->hasOne(City::className(), ['id'=>'city_id']);
}
}
执行代码:
$get_city = 1;
$u = Myuser::find()->joinWith('profile', 0, 'INNER JOIN');
if ($get_city) {
$u->joinWith('profile.city');
}
echo $u->createCommand()->rawSql;
结果:
SELECT `myuser`.* FROM `myuser`
INNER JOIN `profile` ON `myuser`.`id` = `profile`.`user_id`
LEFT JOIN `profile` ON `myuser`.`id` = `profile`.`user_id`
LEFT JOIN `city` ON `profile`.`city_id` = `city`.`id`
如果我需要获得唯一的 table 'profile' 并从 table 'city' 添加字段,我该如何避免重复。如果 table 'city' 中没有字段,则值应为 'null'.
我想这是框架中的一个错误(或功能)。当您使用关系 profile.city
框架看不到 inner join
已经加入的关系...我假设如果您使用 left join
作为第一个关系,一切都会正常。
在您的情况下,请尝试使用 leftJoin()
并指定要加入的 table 名称:
$get_city = 1;
$u = Myuser::find()->innerJoinWith('profile');
if ($get_city) {
$u->leftJoin('city', 'profile.city_id = city.id');
}
echo $u->createCommand()->rawSql;
这是因为您对这两个联接使用了不同的联接类型。 joinWith('profile', false, 'INNER JOIN')
和 joinWith('profile')
将生成不同的 JOIN
(joinWith()
默认使用 LEFT JOIN
作为连接类型),因此您有 2 个连接查询。如果您想避免重复,您可以对这两个 joinWith()
调用使用相同的设置:
$get_city = 1;
$u = Myuser::find()->joinWith('profile', false, 'INNER JOIN');
if ($get_city) {
$u->joinWith('profile.city', false, 'INNER JOIN');
}
echo $u->createCommand()->rawSql;
结果:
SELECT `myuser`.* FROM `myuser` INNER JOIN `profile` ON `myuser`.`id` = `profile`.`user_id` INNER JOIN `city` ON `profile`.`city_id` = `city`.`id`
如果你想结合INNER JOIN
和LEFT JOIN
,你可以使用扩展语法:
$get_city = 1;
if ($get_city) {
$u = Myuser::find()->joinWith(
[
'profile' => function (ActiveQuery $query) {
$query->joinWith('city');
},
],
false,
'INNER JOIN'
);
} else {
$u = Myuser::find()->joinWith('profile', false, 'INNER JOIN');
}
echo $u->createCommand()->rawSql;
结果:
SELECT `myuser`.* FROM `myuser` INNER JOIN `profile` ON `myuser`.`id` = `profile`.`user_id` LEFT JOIN `city` ON `profile`.`city_id` = `city`.`id`
如果您与同一个 table 有多个关系,您应该为它们使用不同的别名。如果不是,Yii 将加入 table,导致错误或重复