给定此模式(在postgresql-9.2中):
CREATE TABLE foo (
id serial PRIMARY KEY,
...other columns elided...
);
CREATE TYPE event_type AS ENUM ('start', 'stop');
CREATE TABLE foo_event (
id serial PRIMARY KEY,
foo_id integer NOT NULL REFERENCES foo (id),
timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
type event_type NOT NULL
);
如何让所有“正在运行”foo
?也就是说,foo
s的最近事件是“开始”,或者甚至更好,foo
s至少启动过一次,并且在最后一次之后没有stop
s { {1}}(如果我将来添加更多事件类型)。
到目前为止,我最好的尝试是:
start
这里的问题当然是它永远不会返回任何曾被停止过的SELECT * FROM foo
WHERE id NOT IN
(SELECT foo_id FROM foo_event
WHERE type='stop');
。
答案 0 :(得分:3)
使用MAX()
聚合来检索每个start
组的最新foo_id
个事件,您可以对检索最新的子查询执行LEFT JOIN
(同时{ {1}})MAX()
事件大于stop
子句中的start
事件。在ON
事件子查询中查找NULL
s的那些,这意味着没有匹配。
stop
注意,如果停止事件可以与其相应的启动事件同时结束,请在SELECT
foo.*,
fstart.*
FROM
foo
INNER JOIN (
/* Left side gets most recent start events */
SELECT
foo_id,
MAX(timestamp) AS start_ts
FROM
foo_event
WHERE event_type = 'start'
GROUP BY foo_id
) fstart ON foo.id = fstart.foo_id
/* Right side gets most recent stop events */
LEFT JOIN (
SELECT
foo_id,
MAX(timestamp) AS stop_ts
FROM
foo_event
WHERE event_type = 'stop'
GROUP BY foo_id
/* JOIN rows that have a greater stop time than start time */
) fstop ON fstart.foo_id = fstop.foo_id AND fstop.stop_ts > fstart.start_ts
/* And find rows where there's no matching stop event greater than the start */
WHERE fstop.stop_ts IS NULL
子句中使用>=
而不是>
...