gpt4 book ai didi

php - Doctrine 在使用 joins 和 offset 时跳过数据集

转载 作者:搜寻专家 更新时间:2023-10-31 20:52:33 24 4
gpt4 key购买 nike

我在 PHP5.3 上的 Symfony 1.4 中使用 Doctrine 1.2。

我有一个数据库,其中事件有多个开始日期时间 (1:n) 和类型 (n:m)。

对于一个节目,我想要一个开始时间和事件标题的列表,它们属于特殊类型并且不会过时:

$dql = Doctrine_Query::create()
->select('ed.start_datetime,e.title')/*edd.*,*/
->from('EventDate ed')
->leftJoin('ed.Event e')
->leftJoin('e.EventTypes et')
->leftJoin('e.Domain d')
->orderBy('ed.start_datetime, ed.event_id');
->where('e.start_datetime >= ? AND e3.id = ?',array('2011-05-27 17:19:41',2))
->fetchArray();

可以在 pastebin.com/SdjvsaxW 查看架构.

现在, Doctrine 有两个陈述

SELECT DISTINCT e5.event_id FROM event_date e5 LEFT JOIN event e6 ON e5.event_id = e6.id LEFT JOIN event_event_type e8 ON (e6.id = e8.event_id) LEFT JOIN event_type e7 ON e7.id = e8.event_type_id WHERE (e5.start_datetime >= '2011-05-27 17:19:41' AND e7.id = '2') ORDER BY e5.start_datetime, e5.event_id

SELECT e.event_id AS e__event_id, e.start_datetime AS e__start_datetime, e2.id AS e2__id, e2.title AS e2__title FROM event_date e LEFT JOIN event e2 ON e.event_id = e2.id LEFT JOIN event_event_type e4 ON (e2.id = e4.event_id) LEFT JOIN event_type e3 ON e3.id = e4.event_type_id WHERE e.event_id IN (*all the IDs from the first query*) AND (e.start_datetime >= '2011-05-27 17:19:41' AND e3.id = '2') ORDER BY e.start_datetime, e.event_id

当我引入分页时问题就开始了:当我添加一个偏移量时,它将被添加到第一个查询中。现在,由于事件可能有多个开始时间,第一个 SELECT DISTINCT 查询的 ID 数可能小于日期数。因此,日期可能会被跳过。在我的例子中,甚至有不到 50 个不同的事件,所以显示事件日期 51-100 的第二页确实是空的,尽管事实上有几百个事件日期(由于重复事件)。

我认为问题可能会得到解决,但我无法控制它。

有人知道吗?

最佳答案

Doctrine 运行两个查询,第一个是不同的,在一种称为“限制子查询”的模式下,当您有一个基表并连接一对多关系时。这是因为您将选择连接的产品,最终得到的行数多于基表中的记录数。例如,如果事件 #5 有两个 EventType,数据库将在两行中返回事件 #5。这两个查询行为仅在 MySQL 中,其他数据库可以在子查询中运行限制,而 Doctrine 生成单个查询。

由于您的事件有多个日期,并且 EventDate 有一个复合主键,Doctrine 应该在第一个查询中选择一组不同的 (event_id, start_datetime),但它似乎忽略了复合主键的第二部分,可能是因为它无法将它们填充到第二个查询的 ON 子句中。

您可以通过以下两种或三种方法之一解决此问题:1) 给 EventDate 添加一个唯一的主键(自增列)。您可能不必在其他任何地方引用它,但 Doctrine 将开始使用它2) 手动执行 2 个查询。从 EventDate 中选择所有不同的 event_id、start_datetime,添加您的限制和偏移量,然后以编程方式创建一个 where 子句:

 ... WHERE ((event_id = ? AND start_datetime = ?) OR (event_id = ? AND start_datetime = ?))... 

3) 重新排序您的查询以从不同的表开始或在选择中添加一个 DISTINCT。尝试选择不同的(ed.event_id,ed.start_datetime)。有时这些东西可以避免触发限制子查询算法。4) 关闭此系统,请参阅下面的链接,从未尝试过,我不确定水合作用和 Doctrine 对象缓存有什么副作用。

就我个人而言,我会选择#1。我发现在 Doctrine 中使用额外的主键列总是有帮助的,即使您可以跨多个列形成主键也是如此。

如果你想查看用于此的代码 Doctrine ,请参阅 lib/Doctrine/Record.php,函数 getLimitSubquery()。您会注意到注释“//复合键怎么样?”在代码中两次。您还可以阅读 http://www.doctrine-project.org/documentation/manual/1_2/en/dql-doctrine-query-language:limit-and-offset-clauses:the-limit-subquery-algorithm

关于php - Doctrine 在使用 joins 和 offset 时跳过数据集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6156520/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com