MySQL过滤掉自引用

标签 mysql sql performance

我们有一个定期查询的事件表(如日历事件中的开始和结束时间):

TABLE event (
  `id` varchar(32) NOT NULL,
  `start` datetime,
  `end` datetime,
  `derivedfrom_id` varchar(32),
  `parent_id` varchar(32) NOT NULL
)
  • parent_id 指向提供一些附加信息的日历表。
  • 一些事件是从另一个事件创建的,因此通过 derivedfrom_id 列有一个指向该“起源”事件的引用。

在检索一组事件时,我们通常按日期(开始/结束)和日历(parent_id)进行查询,并限制数量通过 limit 进行分页的结果数。

我们现在面临的问题:有时我们需要将用户的相关事件合并到一个表示中。所以我们进行正常查询

SELECT id, start, parent_id
FROM event
WHERE parent_id in (<list of calendars>)
  AND start >= 'some date'
LIMIT x

...然后过滤掉原始事件,因为衍生物具有不同的信息并且无论如何都指代它们的起源。

正如您可能已经看到的(比我们看到的更早),我们在过滤之前进行了限制,因此收到一组基数小于我们最初预期的事件,即结果数量低于过滤后的“x”过滤。

我唯一能想到的就是复制查询并进行子选择:

SELECT id, start, parent_id
FROM event
WHERE parent_id in (<list_of_calendars>)
  AND start >= 'some date'
  AND (/* the part below duplicates the previous conditions */
        derivedfrom_id is not null
        or id not in (
          SELECT derivedfrom_id
          FROM event
          WHERE parent_id in (<list_of_calendars>)
            AND start >= 'some date'
            AND derivedfrom_id is not null
        )
      )
LIMIT x

但我几乎不相信这是做到这一点的唯一方法。特别是,因为我们的查询要复杂得多。

有没有更好的办法?


示例数据

(根据评论中的要求)

鉴于这三个事件:

│ *ID* │ *DERIVEDFROM_ID* │ *PARENT_ID* │ *START*
├──────┼──────────────────┼─────────────┼─────────────────
│ 100  │ -                │ A           │ 2014-11-18 15:00
│ 101  │ 100              │ B           │ 2014-11-18 15:00
│ 150  │ -                │ A           │ 2014-11-20 08:00

... 限制为 2,我想获取事件 101 和 150。

相反,使用当前方法:

  • 限制为 2 的查询导致事件 100 和 101
  • 过滤后,丢弃事件100,只剩下101

关于预期答案的注释

上面的SQL实际上是从一个使用JPA的Java应用程序生成的。我目前的解决方案是生成一个 where 子句并复制它。如果有通用的特定于 JPA 的内容,我将不胜感激。

最佳答案

试试这个:

SELECT e.*
FROM `event` e            # 'e' from 'event'
  LEFT JOIN `event` d     # 'd' from 'derived'; `LEFT JOIN` gets ALL entries from `e`
    ON e.id = d.derivedfrom_id    # match an event `e` with all those `d` derived from it
WHERE d.id IS NULL        # keep only events `e` without derived events `d`
;

LEFT JOINe 中选择所有事件,并将它们与派生自它们的事件 d 配对。它确保来自 e所有条目都有机会被选中,无论它们是否具有派生事件。 WHERE 子句只保留 e 中没有派生事件的事件。它保留派生事件以及没有派生事件的原始事件,但去除那些具有派生事件的原始事件。

根据需要在表e的字段上添加额外的WHERE条件,使用LIMIT子句,搅拌均匀,冷食。

关于MySQL过滤掉自引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26998081/

相关文章:

mysql - 如何获取每个组中的最新记录并检查它是否是唯一的记录?

c# - coderush 搜索特定问题

R:按位置(添加、减去或替换的一个元素)查找并计算嵌套在列表中的字符向量之间的所有差异

mysql - 使用聚合函数更新语句

objective-c - 可变数组,Objective-c,或可变数组,c。性能上有什么区别吗?

MySQL-大量删除后如何刷新表

mysql - MAMP存储过程: Commands out of sync error

java - 异常 [EclipseLink-4003](Eclipse 持久性服务 - 2.3.0.v20110604-r9504):

mysql - 如何选择条件存储在表中的mysql行?

mysql - 在一行 SQL 中更新两行不同的行