我有三张桌子:
用户,众议院和众议院事件
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
答案 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
我不清楚您是否只想要最近的“暂停”日期或最近的所有事件。我把它写成了一个内部联接,因为我觉得如果我把它链接到另一个左边的连接中,你可能会遇到问题。
我不明白id
,user_id
和house_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_id
为PRIMARY KEY
表。{/ p>