假设我们有一个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做到这一点?
答案 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
关键字。