是否可以按主键的一部分对 DQL 查询进行分组并返回具有 max() 日期时间记录(早于参考日期)的记录?

Posted

技术标签:

【中文标题】是否可以按主键的一部分对 DQL 查询进行分组并返回具有 max() 日期时间记录(早于参考日期)的记录?【英文标题】:Is it possible to group a DQL query by a portion of the primary key and return records with max() datetime record (earlier than a reference date)? 【发布时间】:2016-09-27 12:13:25 【问题描述】:

在一个原则查询中,我怎样才能group by 只在复合主键中的一些变量?在下面的情况下,CategoryProduct(但不是 Iterator)?

示例

下表应保留价格随时间变化的历史记录 (Transactions)。我正在尝试编写一个学说查询以返回最新的日期记录(在参考日期之前):

Category (PK) | Product (PK) | Iterator (PK) | CreateDT   | Amount
1               1              1               2016-01-01   100
1               1              2               2016-04-01   150
1               2              1               2016-09-01   50
2               1              1               2016-01-01   75
2               1              2               2016-01-31   80
2               1              3               2016-09-01   90

使用上述作为参考,我试图得到的结果是每个类别/产品一条记录如下:

一)。考虑Category=1 并与参考日期2016-02-01 进行比较:

Category (PK) | Product (PK) | Iterator (PK) | CreateDT   | Amount
1               1              1               2016-01-01   100
1               2              1               2016-09-01   50

b)。仅与参考日期2016-02-01 进行比较:

Category (PK) | Product (PK) | Iterator (PK) | CreateDT   | Amount
1               1              1               2016-01-01   100
1               2              1               2016-09-01   50
2               1              2               2016-01-31   80

代码

我的尝试是下面的,但它不起作用(在理想的世界中,我希望 `$category 是可选的):

public function findActiveIterationByDate($category, $refdate)

    return $this->getEntityManager()
        ->createQuery(
            'SELECT b3 
             FROM AppBundle:Transaction t1
             INNER JOIN
             (SELECT t2 
              FROM AppBundle:Transaction t2, max(createDT) as createDT 
              WHERE t2.Category=$category, t2.createDT <= $refdate 
              GROUP BY t2.Category, t2.Product) as t3
             ON t1.Category=t3.Category AND t1.Product=t3.Product'
        )
        ->getResult();

错误

但是,尝试这样做会给我以下错误 - 我不确定问题是我的 INNER JOIN 还是 DQL 无法按部分主键分组?

[Doctrine\ORM\Query\QueryException] [语义错误] 第 0 行,第 102 列靠近 '(SELECT t2 ':错误:未定义类 '('。

【问题讨论】:

【参考方案1】:

错误是因为您不能在JOIN 语句中使用子查询。您可以在DQL syntax declartation 中看到它。更具体地说是 JoinJoinAssociationDeclaration 定义。

我认为您可以将INNER JOIN 语句移动到SELECT 子查询中,并尽可能使WHERE 条件更具限制性,即使这可能会降低性能。

也许更好的是写一个Native SQL 并将结果映射到相对简单且有据可查的 Doctrine 实体。见http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/native-sql.html#the-resultsetmapping。

【讨论】:

感谢@Martin 的回答——我尝试使用复合键的唯一原因是为了最大限度地提高性能。但是,如果它可能降低性能,那么这不是我想要的 - 我将把它们取出并用任意 id 主键替换它们......! 如果性能很重要,那么使用 Native SQL,你可以做任何你想做的事情,只需将结果映射到 Doctrine 实体。

以上是关于是否可以按主键的一部分对 DQL 查询进行分组并返回具有 max() 日期时间记录(早于参考日期)的记录?的主要内容,如果未能解决你的问题,请参考以下文章

Yii——关于无主键的数据表或视图

基础-SQL-DQL-分组查询

SQL中的每一张表都必须设有主键吗

MySQL核心面试技术(持续更新)

mysql基础-mysql中的DQL-分组函数

MySQL笔记--- 部分 DQL 语句;条件查询;排序;分组函数;单行处理函数;group by ,having ;