如何筛选仅购买两款指定商品的客户?现有查询结果不符需求
问题出在哪
你这段代码有几个致命问题导致结果不符合要求:
- 没锁定指定商品:只是统计购买的商品数量为1或2,但完全没限定必须是你指定的那两款,任何买了1-2件不同商品的客户都会被捞进来。
- 统计逻辑拆分错误:把单独订单的商品和套餐里的商品分开判断,用
or连接后,客户哪怕总共买了3种不同商品(比如单独买1种,套餐里2种),也会满足其中一个条件被选中。 - 左连接引入无效数据:
left join orders会保留从未下单的客户,这和“购买过商品”的前提矛盾。
修正后的代码
假设你要找的两款商品ID是[123, 456],调整后的查询如下:
// 替换成你实际要指定的两款商品ID $targetProductIds = [123, 456]; $builderObj = $this->db->table('customers'); // 用inner join确保只保留有有效订单的客户 $builderObj->join('orders', 'customers.id = orders.customer_id', 'inner'); // 合并所有购买记录:单独商品 + 套餐内的商品 $builderObj->join('( SELECT order_id, product_id FROM order_products UNION ALL SELECT op.order_id, opp.product_id FROM order_packages op JOIN order_package_products opp ON op.id = opp.order_package_id ) AS all_purchased', 'orders.id = all_purchased.order_id', 'inner'); $builderObj->select('customers.id, customers.email'); $builderObj->where('customers.deleted_at', null); $builderObj->where('orders.deleted_at', null); $builderObj->whereNotIn('orders.order_process_status_id', [OrderProcessStatusModel::PAYMENT_PENDING, OrderProcessStatusModel::ORDER_CANCELLED]); // 只保留购买过指定商品的记录 $builderObj->whereIn('all_purchased.product_id', $targetProductIds); // 分组后确认客户买过的唯一商品恰好是2种(两款都买过,且没买过其他) $builderObj->groupBy('customers.id'); $builderObj->having('COUNT(DISTINCT all_purchased.product_id)', '=', 2); $builderObj->orderBy('customers.id', 'DESC'); $removeRestoreCustomersArr = $builderObj->get()->getResult('array'); return $removeRestoreCustomersArr;
关键调整说明
- 合并商品来源:用
UNION ALL把单独订单和套餐里的商品合并成一个数据集,统一统计客户所有购买的商品。 - 过滤无效数据:改用
inner join直接排除没下单、没买过商品的客户。 - 锁定目标商品:加
whereIn限定只能是你指定的两款商品。 - 精准统计:分组后用
having确保客户买过的唯一商品数量正好是2,保证他们只买过这两款,没买过其他。
如果你的需求是“买过这两款中的1或2款,且没买过其他商品”,把having条件改成:
$builderObj->having('COUNT(DISTINCT all_purchased.product_id)', '<=', 2);
内容的提问来源于stack exchange,提问作者Goldy-566
相关产品推荐
相关产品推荐

