Yii2框架IN查询重点
问题描述
在Yii2框架中,使用 Query Builder生成查询数据库的SQL时需要注意,在使用IN条件时,传入的参数数组中,如果包含值为NULL的元素,则构建成的SQL会查询对应字段值为NULL的数据。如果不了解这个特性,可能最终构造出的SQL与我们预想的情况会不一样,可能会导致查询出大量的数据,导致程序执行错误。
代码示例
- 根据指定id查询出3条会员数据,再拿到3个会员的unionid去查询3个会员对应的加好友信息
$users = OaUser::find()->select('id, unionid')->where(['id' => [2240, 2241, 2340]])->asArray()->all();
- 取出3个会员的unionid信息
$unionids = array_column($users, 'unionid');
- 此时3个会员中有一个会员没有unionid信息,数据库中这个会员的unionid字段值为NULL,此时 $unionids 变量的值为
$unionids = [
'o2U82s5JFVJmDvZJlhan9HwgCumo',
'o2U82swDId4CfcqLs5g6svAzkWgE',
null
];
- 通过unionid数组并用IN条件去查询对应的加好友数据,可能在预想中,最多会根据两个unionid查询出两条好友数据
$contacts = OaWechatQyExternalContacts::find()->select('id, unionid')->where(['unionid' => $unionids])->asArray()->all();
- 但此时,上面的方法实际生成的SQL如下:
SELECT `id`, `unionid` FROM `oa_wechat_qy_external_contacts` WHERE `unionid` IN ('o2U82s5JFVJmDvZJlhan9HwgCumo', 'o2U82swDId4CfcqLs5g6svAzkWgE') OR `unionid` IS NULL
上面程序会把 OR unionid IS NULL 的条件组合到SQL中,并不会过滤掉查询条件数组中的空值,或者将空值转为空字符串进行查询。这可能会跟我们预想的查询条件不太一样。
由于好友表中有大量unionid为NULL的数据,所以上面程序会查询出非常多的数据,导致程序执行错误
解决方案
如果我们只想查询出unionid不为空的数据时,应该对 IN 查询条件的数组参数进行过滤,将其中的空值去掉,这样构造出来的SQL和查询结果就是符合预期的了
# 获取到unionid数据后,将空值过滤掉
$unionids = array_filter(array_column($users, 'unionid'));
-- 构造的SQL:
SELECT `id`, `unionid` FROM `oa_wechat_qy_external_contacts` WHERE `unionid` IN ('o2U82s5JFVJmDvZJlhan9HwgCumo', 'o2U82swDId4CfcqLs5g6svAzkWgE')
补充
如果 IN 查询条件的参数是一个空数组,那么构造出的SQL语句如下:
SELECT `id`, `unionid` FROM `oa_wechat_qy_external_contacts` WHERE 0=1