使用最后一条记录来满足JOIN

时间:2015-10-09 17:32:57

标签: sql postgresql join

我有三张桌子:

用户,众议院和众议院事件

House有一个foreign_key(user_id)给User,一个HouseEvent有一个foreign_key(house_id)到House

我希望能够让所有没有房子拥有最后关联事件名称的房子的用户(并非所有房屋都有事件虽然)

我现在采用的方法是通过这样做来吸引没有房屋的用户或任何被暂停的用户:

SELECT User.name FROM User
LEFT JOIN House h on h.user_id = user.id
LEFT JOIN HouseEvent e on h.user_id = e.house_id
WHERE h.user_id IS NULL OR e.name = 'suspended'
GROUP BY User.name

我如何修改该查询,以便我获得所有没有房屋的用户以及那些拥有任何上次事件被暂停的房屋的用户。在上面的查询中,我只考虑是否存在任何暂停事件,而不考虑与该房屋相关的最后一个事件。

这是SQL小提琴:http://sqlfiddle.com/#!9/e0f235

2 个答案:

答案 0 :(得分:0)

我建议这样的事情。我必须参考小提琴中的模式来获取一些信息:

SELECT u.name
FROM
    User u
    LEFT JOIN House h on h.user_id = u.id
    LEFT JOIN (
        HouseEvent e INNER JOIN (
            SELECT house_id, max(date) AS max_date
            FROM HouseEvents
            GROUP BY house_id
        ) e2
            ON e2.house_id = e.house_id AND e2.max_date = e.date
    ) on h.user_id = e.house_id
WHERE h.user_id IS NULL OR e.name = 'suspended'
GROUP BY u.name

我不清楚您是否只想要最近的“暂停”日期或最近的所有事件。我把它写成了一个内部联接,因为我觉得如果我把它链接到另一个左边的连接中,你可能会遇到问题。

我不明白iduser_idhouse_id是如何引用相同的东西的。

答案 1 :(得分:0)

这是WINDOW FUNCTIONS的完美用例,我认为这可以提高查询的可读性:

object

神奇发生在行SELECT DISTINCT user_name FROM ( SELECT u.name as user_name, h.user_id as house_user_id, /*1*/ last_value(e.name) OVER (PARTITION BY u.id ORDER BY e.date ASC NULLS FIRST) as last_event_for_user FROM User u LEFT JOIN House h ON h.user_id = u.id LEFT JOIN HouseEvent e ON h.user_id = e.house_id /*2*/ ) as sub WHERE sub.house_user_id IS NULL OR sub.last_event_for_user='suspended' 中,我们按特定顺序(以及每个/*1*/)获取name列的最后一个值。然后在更高级别的查询中,我们只获取没有房子的行和那些暂停'作为最后一次活动。

脚注:我相信你的联合表达(user_id)是正确的,/*2*/ user_idPRIMARY KEY表。{/ p>