1

このスキーマが与えられた場合 (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最新のイベントが「開始」であるfoos、またはさらに良いことに、少なくとも 1 回開始されstop、最後のイベントの後に sがないstart(将来さらにイベント タイプを追加する場合に備えて) s です。


これまでの私の最善の試みは次のとおりです。

SELECT * FROM foo
 WHERE id NOT IN
 (SELECT foo_id FROM foo_event
  WHERE type='stop');

fooもちろん、ここでの問題は、これまで停止されたことのある s が返されないことです。

4

1 に答える 1

3

集計を使用してグループごとにMAX()最新のイベントを取得すると、句内のイベントよりも大きい最新の (また)イベントを取得するサブクエリに対して実行できます。イベント サブクエリでsを含むものを探します。これは、一致しないことを意味します。startfoo_idLEFT JOINMAX()stopstartONNULLstop

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

そして、それを見てください、それは実際に機能します!http://sqlfiddle.com/#!12/8642d/1

停止イベントが対応する開始イベントと同時に終了できる場合は、句で>=はなく使用してください...>ON

于 2013-02-20T03:21:55.143 に答える