如何在教义中进行复杂的SQL查询

Posted

技术标签:

【中文标题】如何在教义中进行复杂的SQL查询【英文标题】:How to make complicated SQL query in doctrine 【发布时间】:2016-09-22 18:30:21 【问题描述】:

我有 2 个表:users 和他们的 points

用户有字段:

id

姓名

点有字段:

id

开始日期

结束日期

count_of_points

user_id

所以有些用户可能有或没有积分。积分条目受时间间隔限制(从 start_dateend_date),并且有用户在此间隔内拥有的积分计数。

我现在需要显示按总和排序的用户表(时间戳必须在 start_dateend_date 之间)并稍后在视图中显示这个总和值。如果用户没有积分,则此计数必须等于 0。

我有这样的事情:

$qb = $this->getEntityManager()
        ->getRepository('MyBundle:User')
        ->createQueryBuilder('u');
    $qb->select('u, SUM(p.count_of_points) AS HIDDEN sum_points')
        ->leftJoin('u.points', 'p')
        ->orderBy('sum_points', 'DESC'); 
$qb->groupBy('u');
        return $qb->getQuery()
            ->getResult();

但这没有日期间隔的限制,也没有我可以在对象视图中使用的总和点字段。

我试图找到如何解决这个任务,我在 SQL 中做了这样的事情:

SELECT u.*, up.points FROM users AS u LEFT OUTER JOIN
      (SELECT u.*, SUM(p.count_of_points) AS points FROM `users` AS u
      LEFT OUTER JOIN points AS p ON p.user_id = u.id
      WHERE p.start_date <= 1463578691 AND p.end_date >= 1463578691
      ) AS up ON u.id = up.id ORDER BY up.points DESC

但是这个查询只给了我在积分表中有条目的用户,所以我认为我必须使用另一个 JOIN 来添加没有积分的用户。这是一个复杂的查询。我不知道如何在学说中实现这一点,因为 DQL 不能使用带有 LEFT JOIN 的内部查询。

也许还有其他方法可以解决此任务?也许我的表格架构是错误的,我可以用不同的方式来做吗?

【问题讨论】:

【参考方案1】:

编辑:忘记了日期条件。更正答案:

在普通的 mysql 中,您的查询将如下所示:

SELECT u.id, u.name, COALESCE(SUM(p.count_of_points),0) AS sum_points 
FROM Users u 
LEFT JOIN Points p ON p.user_id=u.id 
WHERE (p.start_date <= 1463578691 AND p.end_date >= 1463578691) OR p.id IS NULL
GROUP BY u.id
ORDER BY sum_points DESC

COALESCE 函数返回第一个非 NULL 参数,因此如果用户没有积分,则总和将导致 NULL,但 COALESCE 为 0。

我不确定使用 Doctrine 查询生成器的翻译,但您可以尝试:

$qb = $this->getEntityManager()->createQueryBuilder();

$qb->select('u')
   ->addSelect('COALESCE(SUM(p.count_of_points),0) AS sum_points')
   ->from('User', 'u')
   ->leftjoin('u.points', 'p')
   ->where('(p.start_date <= ?1 AND p.end_date >= ?1) OR p.id IS NULL')
   ->groupBy('u.id')
   ->orderBy('sum_points','DESC')
   ->setParameter(1, $date_now);

【讨论】:

不幸的是,您的变体只为用户提供积分条目。 纯 SQL 还是 DQL 查询?因为我测试了普通 SQL,它给了所有用户,包括那些没有积分的用户。 好的,我看到了问题,我忘记了测试中的日期条件...当用户没有积分时,LEFT JOIN 子句将返回一行带有 u.id 和 u 的结果。名称已填充,并且 p.id = NULL、p.start_date=NULL、p.end_date=NULL... 因此,为了不从请求中排除这些行,请在 WHERE 中添加“OR p.id IS NULL”子句。

以上是关于如何在教义中进行复杂的SQL查询的主要内容,如果未能解决你的问题,请参考以下文章

教义:从原始 SQL 中水合模型

如何在 symfony 2 和教义 2 中自定义 sql 日志?

如何使用 symfony 在教义查询构建器中选择表之间的特定连接?

教义 2 - 从 $em->find() 获取 SQL

如何使用 DISTINCT 在 NHibernate SQL 查询中进行分页

如何对唯一查询进行复杂计数