使用内连接和左连接时 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') 将生成不同的 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`

如果您与同一个 table 有多个关系,您应该为它们使用不同的别名。如果不是,Yii 将加入 table,导致错误或重复