选择关联表的最后一行具有特定值

时间:2015-10-12 22:00:40

标签: sql postgresql join greatest-n-per-group

我有两张桌子:

User (id, name)
UserEvent (id, user_id, name, date)

如何让最后一个(按日期排序)UserEvent.name的值为''?

的所有用户

我在SQLFiddle上写了一个示例,其中包含一些特定的数据:http://sqlfiddle.com/#!9/b76e24 - 对于这种情况,我只会得到' Mery'来自表User,因为即使约翰'已关联的事件名称最后一个未被播放'。

3 个答案:

答案 0 :(得分:1)

这可能是最快的:

SELECT u.*
FROM   usr u  -- avoiding "User" as table name
JOIN   LATERAL (
   SELECT name
   FROM   userevent
   WHERE  user_id = u.id
   ORDER  BY date DESC NULLS LAST
   LIMIT  1
   ) ue ON ue.name = 'played';

LATERAL需要Postgres 9.3 +

或者你可以使用DISTINCT ON(每个用户几行更快):

SELECT u.*
FROM   usr u  -- avoiding "User" as table name
JOIN   (
   SELECT DISTINCT ON (user_id)
          user_id, name
   FROM   userevent
   ORDER  BY user_id, date DESC NULLS LAST
   ) ue ON ue.user_id = u.id
       AND ue.name = 'played';

DISTINCT ON的详细信息:

带有效测试用例的

SQL Fiddle

如果定义date NOT NULL,则不需要NULLS LAST。 (在下面的索引中都没有。)

读取两者的效果的关键,尤其是第一个查询是匹配的多列索引

CREATE INDEX userevent_foo_idx ON userevent (user_id, date DESC NULLS LAST, name);

除此之外:切勿使用reserved words作为标识符。

答案 1 :(得分:0)

按用户ID返回用户事件分组的最大日期。获取结果集并通过用户ID和最大日期将其连接回用户事件,并仅过滤播放的记录。

答案 2 :(得分:0)

这是:

首先,我从每个用户处获取MAX ID并使用此ID将其加入ROW 为了测试状态是否“播放”,如果是,我得到他们的用户名。

SELECT
  ids.*,
  u.name,
  ue.*
FROM (
  SELECt max(id) AS id from UserEvent
  GROUP by  user_id
) as ids
LEFT JOIN UserEvent ue ON ue.id = ids.id
LEFT JOIN User u ON u.id  = ue.user_id
WHERE ue.name = 'played';