我们有一个定期查询的事件表(如日历事件中的开始和结束时间):
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 JOIN
从 e
中选择所有事件,并将它们与派生自它们的事件 d
配对。它确保来自 e
的所有条目都有机会被选中,无论它们是否具有派生事件。 WHERE
子句只保留 e
中没有派生事件的事件。它保留派生事件以及没有派生事件的原始事件,但去除那些具有派生事件的原始事件。
根据需要在表e
的字段上添加额外的WHERE
条件,使用LIMIT
子句,搅拌均匀,冷食。
关于MySQL过滤掉自引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26998081/