使用内部联接和jeft联接时的Yii2关系重复

时间:2018-11-15 20:03:30

标签: php sql yii2 relation

共有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查询重复表关系'tbl_b'。你知道为什么吗?

更新

好的,我更详细地研究了我的问题。 如果使用不同的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`

如果我需要获取唯一的表“个人资料”并从表“ city”中添加字段,如何避免重复。如果表“ city”中没有字段,则值应为“ null”。

2 个答案:

答案 0 :(得分:0)

我想这是框架中的错误(或功能)。当您使用关系profile.city框架时,看不到inner join已经加入的关系...我认为,如果您对第一个关系使用left join,一切都会很好。

在您的情况下,请尝试使用leftJoin()并指定要联接的表名:

$get_city = 1;
$u = Myuser::find()->innerJoinWith('profile');
if ($get_city) {
    $u->leftJoin('city', 'profile.city_id = city.id');
}
echo $u->createCommand()->rawSql;

答案 1 :(得分:0)

这是因为您为这两个联接使用了不同的联接类型。 joinWith('profile', false, 'INNER JOIN')joinWith('profile')将生成不同的JOINjoinWith()默认使用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 JOINLEFT 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`