仅在特定日期之后选择带有条形事件的foo

时间:2014-01-26 11:13:46

标签: mysql sql select join

考虑两个表:

Foo:
  id INT,
  name VARCHAR

Bar:
  id INT,
  foo_id INT REFERENCES Foo(id),
  event SET('hit','miss'),
  ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP

每个Foo项目可以有多个Bar事件。 如何在特定日期时间之后查询拥有条形码事件的Foo项目,但在该日期时间之前没有条形码事件?

例如,考虑:

Foo id=1:
    hit 2014-01-21
    hit 2014-01-22
    hit 2014-01-23

Foo id=2:
    hit 2014-01-17
    hit 2014-01-19
    hit 2014-01-21

Foo id=3:
    hit 2014-01-14
    hit 2014-01-15
    hit 2014-01-18

Foo id=4:
    hit 2014-01-21
    hit 2014-01-22
    hit 2014-01-24

我想仅查询2014-01-20之后或之后点击的那些Foo项,因此应返回ID 14

我尝试将Bar表加入到自身中,使用以下几种变体:

SELECT
    b1.id
FROM
    Bar b1 JOIN Bar b2 using (foo_id)
WHERE
    b1.ts > '2014-01-20';

但是,我没有看到如何用WHERE子句来排除2014-01-20之前任何日期的任何组合。

1 个答案:

答案 0 :(得分:2)

SELECT   Foo.*
FROM     Foo JOIN Bar ON Bar.foo_id = Foo.id
GROUP BY Foo.id
HAVING   MIN(Bar.ts) >= '2014-01-20'

或者:

SELECT   Foo.*
FROM     Foo JOIN (
           SELECT   foo_id id, MIN(ts) min_ts
           FROM     Bar
           GROUP BY id
         ) t USING (id)
WHERE    t.min_ts >= '2014-01-20'

或者:

SELECT   Foo.*
FROM     Foo JOIN Bar ON Bar.foo_id = Foo.id
GROUP BY Foo.id
HAVING   SUM(Bar.ts >= '2014-01-20')
 AND NOT SUM(Bar.ts <  '2014-01-20')

或者:

SELECT   *
FROM     Foo
WHERE    EXISTS (
           SELECT *
           FROM   Bar
           WHERE  Bar.foo_id = Foo.id
              AND Bar.ts >= '2014-01-20'
         )
 AND NOT EXISTS (
           SELECT *
           FROM   Bar
           WHERE  Bar.foo_id = Foo.id
              AND Bar.ts <  '2014-01-20'
         )

或者:

SELECT   b1.foo_id
FROM     Bar b1 LEFT JOIN Bar b2
      ON b2.foo_id = b1.foo_id
     AND b2.ts <  '2014-01-20'
WHERE    b1.ts >= '2014-01-20'
     AND b2.foo_id IS NULL
GROUP BY b1.foo_id