You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Yii2中使用leftJoin能否将关联表结果存入子数组?

问题场景与疑问

假设数据库中Product表与Account表存在关联,使用joinWith()查询时:

$products = Product::find()->joinWith('account')->asArray()->all();

返回结果会将Account数据存入子数组:

[
    'title' => 'Product title',
    'price' => 'Product price',
    'accountId' => 1,
    'account' => [
        'id' => 1,
        'name' => 'Account name',
        'location' => 'Account location'
    ]
]

而使用leftJoin()查询时:

$products = Product::find()
    ->select('Product.*')
    ->leftJoin('Account', 'Account.id = Product.accountId')
    ->addSelect([
        'Account.name as accountName',
        'Account.location as accountLocation',
    ])
    ->all();

返回的Account字段是和Product字段平级的:

[
    'title' => 'Product title',
    'price' => 'Product price',
    'accountId' => 1,
    'accountName' => 'Account name',
    'accountLocation' => 'Account location'
]

疑问:能否通过leftJoin()实现将关联表结果存入子数组的效果?

实现方法

当然可以,leftJoin()本身仅返回扁平字段结构,需要通过额外处理来组装子数组,以下是几种实用方案:

方案1:手动遍历重组数组

执行leftJoin查询后,遍历结果集,将指定字段提取为子数组:

// 执行leftJoin查询,获取包含Account字段的扁平结果
$products = Product::find()
    ->select('Product.*, Account.name, Account.location')
    ->leftJoin('Account', 'Account.id = Product.accountId')
    ->asArray()
    ->all();

// 遍历重组account子数组
foreach ($products as &$product) {
    // 组装account子数组
    $product['account'] = [
        'name' => $product['name'],
        'location' => $product['location']
    ];
    // 移除平级的冗余字段
    unset($product['name'], $product['location']);
}
unset($product); // 释放引用变量

方案2:在模型中通过afterFind自动处理

如果使用ActiveRecord对象而非数组结果,可以在Product模型中重写afterFind方法,自动将平级的Account字段封装为子数组:

class Product extends ActiveRecord
{
    // 定义用于存储Account数据的属性
    public $account;

    public function afterFind()
    {
        parent::afterFind();
        // 检查是否存在Account相关字段,存在则组装子数组
        if (isset($this->name, $this->location)) {
            $this->account = [
                'name' => $this->name,
                'location' => $this->location
            ];
            // 移除平级字段
            unset($this->name, $this->location);
        }
    }

    // 其他模型逻辑代码...
}

之后执行leftJoin查询时,返回的Product对象会自动包含account子数组。

方案3:利用数据库JSON函数构造子数组(数据库依赖)

部分数据库(如PostgreSQL、MySQL 8.0+)支持JSON构造函数,可以在select语句中直接生成JSON格式的子数组:

// MySQL 8.0+ 用法
$products = Product::find()
    ->select([
        'Product.*',
        "JSON_OBJECT('name', Account.name, 'location', Account.location) as account"
    ])
    ->leftJoin('Account', 'Account.id = Product.accountId')
    ->asArray()
    ->all();

// 需要将JSON字符串转为数组的话,可添加处理
foreach ($products as &$product) {
    $product['account'] = json_decode($product['account'], true);
}

注意这种方式依赖特定数据库的功能,跨数据库移植性较差。

内容的提问来源于stack exchange,提问作者daniil sidorov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 05:29:57