YII2 Activerecord 实现复杂关联查询

今天需要实现一个比较复杂的SQL,需要LEFT JOIN扩展字段表的工单ID,同时还要匹配扩展字段的值

首先我们把工单表的主键ID和扩展字段的item_id关联起来

public function getExt_field()
    {
    	/**
    	 * 第一个参数为要关联的字表模型类名称,
    	 *第二个参数指定 通过子表的 item_id 去关联主表的 id 字段
    	 */
    	return $this->hasMany(BbItemExtFieldData::className(), ['item_id' => 'id']);
    }

我们通过joinWith就可以关联这两张表了,并实现对工单表的搜索条件约束

BbItem::find()->asArray()->joinWith('ext_field')->where([BbItem::tableName().'.status'=>'1'])->andWhere($where);

然后我们需要把扩展字段的约束条件加上,如果我们的扩展字段表的字段名是扩展字段的名称那么就很好办,不过问题是:

扩展字段表是通过tablekey_name来存储,自定义字段的字段名的

所以我们需要添加 … AND ( (表名.tablekey_name=’字段名’ AND 表名.value=’搜索值’) OR (表名.tablekey_name=’字段名’ AND 表名.value=’搜索值’))的SQL来进行约束

查了半天YII2的手册,终于找到了正确的实现方法:

//进行搜索
		$query = BbItem::find()->asArray()->joinWith('ext_field')->where([BbItem::tableName().'.status'=>'1'])->andWhere($where);
		//追加扩展字段条件
		$ext = ['OR'];
		foreach($category_info['ext_field'] as $k => $one)
		{
			if(isset($ext_where[$one['table_keyname']])) {
				$table_key_name = $one['table_keyname'];
				
				$ext[] = ['AND',
				BbItemExtFieldData::tableName().'.table_keyname=\''.$table_key_name.'\'',
				BbItemExtFieldData::tableName().'.value=\''.$ext_where[$table_key_name].'\'',
				BbItemExtFieldData::tableName().'.ext_id=\''.$one['id'].'\''];
			}
			
			
		}

		$query->andWhere($ext);

这样实现出来的sql是

SELECT `bb_item`.* FROM `bb_item` INNER JOIN `bb_item_ext_field_data` ON `bb_item`.`id` = `bb_item_ext_field_data`.`item_id` 
WHERE `bb_item`.`status`='1' AND `bb_item`.`category_id`='8'
AND ((`bb_item_ext_field_data`.`table_keyname`='ext_field3' AND `bb_item_ext_field_data`.`value`='选项1|选项2' AND `bb_item_ext_field_data`.`ext_id`='5') 
OR (`bb_item_ext_field_data`.`table_keyname`='ext_field4' AND `bb_item_ext_field_data`.`value`='选项1' AND `bb_item_ext_field_data`.`ext_id`='6'))