当前位置: 首页 > 后端技术 > PHP

YII2关系型数据表组装

时间:2023-03-29 15:04:31 PHP

前言每个新手程序员都会遇到一些奇怪的问题。比如有两个或两个以上的数据关系表,就需要用一个主表来查询对应的关系表。数据,下面的关系表描述了数据表的准备,并说明了用户表(user)会员卡表(vip)会员卡附件表(vip_fields)使用场景列表中可以使用和需要查询的接口需求关联多表字段会员卡列表需要有会员昵称/头像/姓名/性别E-mail地址/会员id基于(会员卡)实现关联,找出会员用户信息和会员卡附件数据,以下是两个例子例子1offset(0)->limit(10)->asArray()->all();//循环组装会员用户信息和会员卡附表数据foreach($vipsas&$row){//获取会员卡用户信息$row['user']=User::find()->andWhre(['user_id'=>$row['user_id']])->limit(1)->asArray()->one();//获取会员卡补充信息$row['fields']=VipFIelds::find()->andWhere(['vip_id'=>'vip_id'])->limit(1)->asArray()->one();}返回$vips;?>运行结果[{"vip_id":1,"user_id":1,"user":{"user_id":1,"昵称":"小白","头像":"http://xiaobai.png"},"fields":{"vip_id":1,"realname":"小白","sex":1,"email":"xiaobai@qq.com"}},{"vip_id":2,"user_id":2,"user":{"user_id":2,"昵称":"小米","头像":"http://xiaobai.png"},"fields":{"vip_id":2,"realname":"xiaomixiaomi","sex":1,"email":"xiaomi@qq.com"}}]例2offset(0)->limit(10)->asArray()->all();//用户id$userIds=array_unique(array_column($vips,'user_id'));//会员卡id$vipIds=array_unique(array_column($vips,'vip_id'));//会员卡用户信息数据列表$users=User::find()->andWhere(['user_id'=>$userIds])->asArray()->limit(count($userIds))->all();//以user_id为key重构会员卡信息数据$usersRow=array_column($users,null,'user_id');//会员卡附表数据列表$fields=VipFields::find()->andWhere(['vip_id'=>$vipIds])->asArray()->limit(count($vipIds))->all();//以vip_id为key重组会员卡数据$fieldsRow=array_column($fields,null,'vip_id');foreach($vipsas&$row){//如果组装的会员卡用户信息不存在则为null$row['user']=$usersRow[$row['user_id']]??无效的;//如果组装的会员卡补充信息不存在则为null$row['fields']=$fieldsRow[$row['vip']]??null;}return$vips;?>运行结果[{"vip_id":1,"user_id":1,"user":{"user_id":1,"昵称":"小白","头像":"http://xiaobai.png"},"fields":{"vip_id":1,"realname":"小白白","sex":1,"email":"xiaobai@qq.com"}},{"vip_id":2,"user_id":2,"user":{"user_id":2,"nickname":"小米","avatar":"http://xiaobai.png"},"fields":{"vip_id":2,"realname":"xiaomi","sex":1,"email":"xiaomi@qq.com"}}]Yii特殊用法分析YiijoinWith()用法官方说明该方法会允许您重用现有的关联定义来执行JOIN查询根据指定关联的定义,此方法将一个或多个JOIN语句附加到当前语句。如果$eagerLoading参数为真,该方法也会对指定的关联进行预加载,相当于对指定的关联调用with()。请注意,您需要消除列名的歧义,因为将执行JOIN查询。此方法与with()的不同之处在于它将为主表构建并执行JOINSQL语句。而当$eagerLoading为真时,除了指定关联之外,还会调用with()。在yii\db\ActiveRecord类中定义关联时,使用该方法指定连接表如下://指定连接会员卡调度publicfunctiongetFields(){return$this->hasOne(VipFields::class,['vip_id'=>'vip_id']);}//指定连接会员卡用户表publicfunctiongetUser(){return$this->hasOne(User::class,['user_id'=>'user_id']);}注意以下几点:1.当表名中有下划线时,joinWith中表名的首字母要小写,下划线结束后的首字母要大写。2.有where条件时,字段名前的表名可能是跨数据库的,数据库名必须写全。使用上面的需求场景使用joinWith(['fields','user']);$list=$query->offset(0)->limit(10)->asArray()->all();return$list;?>Vip模型连接使用joinWith时,同时使用field和User模型连接,则表示以vip作为主表,vip_fields和user表作为附表。同时三张表必须有关联数据才有查询结果-操作结果[{"vip_id":1,"user_id":1,"user":{"user_id":1,"nickname":"小白","avatar":"http://xiaobai.png"},"fields":{"vip_id":1,"realname":"小小白","sex":1,"email":"xiaobai@qq.com"}},{"vip_id":2,"user_id":2,"user":{"user_id":2,"昵称":"小米","头像":"http:///xiaobai.png"},"fields":{"vip_id":2,"realname":"Xiaomi","sex":1,"email":"xiaomi@qq.com"}}]后例1foreach中的数据查询,数据库请频繁请求导致数据库压力大。数据库请求次数为1+(N*2)次,对数据库影响很大。示例2查询会员卡主表后,将关联表的关联id单独取出放入数组中,然后批量处理列表查询,重组,数据库请求次数3次总结不同的需求有不同的代码处理逻辑。以例1和例2为例。示例1虽然也能满足接口要求,但是对数据库的影响比较大,不推荐使用。,example1虽然处理步骤较多,但是对数据的影响较小,可以选择example2来使用,如果找到更好的方案,会继续优化