【问题标题】:Yii2 relation duplicate when use inner join and jeft join使用内连接和左连接时Yii2关系重复
【发布时间】:2018-11-15 20:03:29
【问题描述】:

它们之间有 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' 表中没有字段,则 value 应为 'null'。

【问题讨论】:

  • 你能在这里展示一些真实的代码作为例子吗?这些代码 sn-ps 不是有效的 PHP 代码,所以很难理解你的问题。
  • A->joinWith('b.c')->where(''); 的情况似乎没有帮助
  • @rob006 我更新了我的问题。

标签: php sql yii2 relation


【解决方案1】:

我猜这是框架中的一种错误(或功能)。当您使用关系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;

【讨论】:

  • 你说得对,我也这样做了。但我想使用关系)
  • 所以,它现在为我解答。
【解决方案2】:

这是因为您对这两个连接使用了不同的连接类型。 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`

【讨论】:

  • 好的,你会告诉我什么。 $get_city = 1; $u = Myuser::find()->joinWith('profile', 0, 'INNER JOIN'); if ($get_city) { $u->joinWith('profile.city'); } $get_country = 1; $u = Myuser::find()->joinWith('profile', 0, 'INNER JOIN'); if ($get_country ) { $u->joinWith('profile.get_country'); } echo $u->createCommand()->rawSql;
【解决方案3】:

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

【讨论】:

  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
猜你喜欢
  • 1970-01-01
  • 2018-03-06
  • 2021-10-15
  • 2011-07-18
  • 1970-01-01
  • 1970-01-01
  • 2017-08-15
  • 2015-03-04
  • 2018-07-31
相关资源
最近更新 更多