Symfony / Doctrine在日期时间字段中按日计算条目

时间:2015-11-24 16:39:00

标签: mysql symfony date datetime doctrine-orm

假设我们有一个Symfony实体,包含id(int),title(字符串)和created(datetime)字段。

我现在需要按日计数,比如

day, amount
2015-11-22, 5
2015-11-23, 2
2015-11-24, 0

目前我只是加载所有条目(当前月份),在PHP中循环它们并在日期时间上调用format('Y-m-d')来获取当天,然后我将那个存储在包含日期的数组中key和amount作为值(如果日期在数组中,只需增加1,否则将值设置为1)。

必须有更好的方法,我很确定,我应该能够直接在数据库上计算它。

使用普通的SQL我会做类似

的事情
SELECT DATE(created) AS day, COUNT(DISTINCT id) AS amount 
FROM testtable 
GROUP BY DATE(created)

修改:由于查询将使用COUNT()作为主要密钥,并且通过该唯一标识,此处不需要COUNT(DISTINCT id)COUNT(id)会产生完全相同的结果。如果我会对标题执行计数,但我想只计算唯一标题,则需要DISTINCT中的COUNT()关键字,就好像有人在想。

但是我怎么能用Symfony / Doctrine做到这一点?

1 个答案:

答案 0 :(得分:1)

我已经找到了解决方案,并希望,这可以帮助其他有类似问题的人。

首先,Doctrine没有Date函数,因为并非所有数据库系统本身都支持Date。构建Doctrine是为了能够与所有主要数据库系统一起工作,所以这里没有本地Date

要为MySQL添加日期函数(不确定其他数据库),我们可以创建一个新类,让我们称之为DQLDate。我看起来像这样:

<?php
namespace Foo\BarBundle\DQL;

use \Doctrine\ORM\Query\AST\Functions\FunctionNode,
    \Doctrine\ORM\Query\SqlWalker,
    \Doctrine\ORM\Query\Parser,
    \Doctrine\ORM\Query\Lexer;

/**
 * Extracts the date form a timestamp (Mysql function)
 * DQLDate :: DATE ( date as Y-m-d )
 */
class DQLDate extends FunctionNode 
{

    protected $date;

    public function getSql(SqlWalker $sqlWalker) 
    {
       return 'DATE(' . $sqlWalker->walkArithmeticPrimary($this->date) .')';
    }

    public function parse(Parser $parser) 
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->date = $parser->ArithmeticPrimary();
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }

}

接下来,我们需要在config.yml文件中注册该功能。

# Doctrine Configuration
doctrine:
    ...
    orm:
        ...
        dql:
            datetime_functions:
                DATE: Foo\BarBundle\DQL\DQLDate

然后我们都准备好了。

如果我们假设SQL查询

SELECT DATE(created) AS day, COUNT(DISTINCT id) AS amount 
FROM testtable 
GROUP BY DATE(created)

我们现在可以将其转换为

$q = $this->getEntityManager()->createQueryBuilder()
    ->select('DATE(e.created) AS day, COUNT(DISTINCT e.id) AS amount')
    ->from('FooBarBundle:TestTable', 'e')
    ->groupBy('day');
$result = $q->getQuery()->getResult();

如问题中所述,如果字段是唯一的,则DISTINCT中的COUNT关键字不是必需的。如果我们将标题计算为例,我们想知道有多少不同的标题,那么我们需要DISTINCT关键字。