如何用Doctrine QueryBuilder获取每个ArticleID的最早库存实体?
解决方案:通过子查询匹配每个ArticleID的最早记录
当然可以实现!你遇到的问题是直接用groupBy时,Doctrine并不会自动帮你取每组中date最早的那条记录——它只是按分组字段做聚合,返回的是每组的任意一条结果,所以orderBy无法影响分组后的最终取值。
正确的思路是先通过子查询获取每个符合条件的ArticleID对应的最早日期,再将主表与这个子查询关联,筛选出匹配的完整实体记录。下面是具体的Doctrine QueryBuilder实现:
// 第一步:构建子查询,获取每个目标ArticleID的最小日期 $subQuery = $this->getModelManager()->createQueryBuilder() ->select('sub.articleId, MIN(sub.date) as minDate') ->from(InventoryItem::class, 'sub') ->where('sub.articleId IN (:articleIds)') ->andWhere('sub.quantity > 0') ->groupBy('sub.articleId') ->getDQL(); // 第二步:主查询关联子查询,筛选出匹配的完整记录 $rows = $this->getModelManager()->createQueryBuilder() ->select('ii') ->from(InventoryItem::class, 'ii') ->join( sprintf('(%s)', $subQuery), // 将子查询作为临时表关联 'subQ', 'WITH', 'ii.articleId = subQ.articleId AND ii.date = subQ.minDate' ) ->where('ii.articleId IN (:articleIds)') ->andWhere('ii.quantity > 0') ->setParameter('articleIds', $articleIds) ->getQuery() ->getResult();
代码逻辑说明:
- 子查询部分:针对
articleId在指定列表、quantity>0的记录,按articleId分组,计算每组的最小date,得到每个ArticleID对应的最早日期映射。 - 主查询部分:将主表与子查询结果做关联,只保留
articleId和date同时匹配子查询结果的记录,这样就确保了每个ArticleID仅返回date最早的那条实体。
用你的测试数据验证,这个查询会返回:
ID | ArticleID | Quantity | Date 2 | 200 | 20 | 2018-07-31 3 | 100 | 40 | 2018-05-31
完全符合你的期望。如果需要对最终结果做排序,直接在主查询末尾添加->orderBy('ii.articleId', 'ASC')(或其他排序规则)即可,不会影响分组筛选的逻辑。
内容的提问来源于stack exchange,提问作者Torben
相关产品推荐
相关产品推荐

