postgresql:根据最新的透视行进行选择

postgresql:根据最新的透视行进行选择,postgresql,Postgresql,给出一个简单的模式: users ----- - id<int> - name<string> organisations ------------- - id<int> - name<string> organisations_users ------------------- - id<int> - userId<int> - organisationId<int> - joinedAt<date&

给出一个简单的模式:

users
-----
- id<int>
- name<string>

organisations
-------------
- id<int>
- name<string>

organisations_users
-------------------
- id<int>
- userId<int>
- organisationId<int>
- joinedAt<date>
此时,用户[1,3]在组织2中,用户2在组织3中。没有人在组织1中

预期结果 如果我试图让组织2中的每个人都参与进来,我将获得用户1和3(以及他们的
联合日期
日期):

我不会得到用户2,因为尽管该用户最初在组织2中,但该用户随后加入了组织3。

这应该可以做到:

select u.id, u.name, ou.organisationId, ou.joinedat
from users u
  join (
     select userid, organisationid, joinedat, 
            max(joinedat) over (partition by userid) as last_join 
     from organisations_users
  ) ou on u.id = ou.userid and ou.joinedat = ou.last_join
where ou.organisationid = 2;
这假设一个用户不能同时在两个组织中。因此,最新的joinedat值标识用户的当前组织

如果用户可以同时加入多个组织,则需要将
max(joinedat)over(按用户ID划分)
更改为
max(joinedat)over(按用户ID划分,按组织ID划分)


另一个选项是使用
distinct on()
而不是窗口函数。通常,
distinct on()
解决方案的性能更好:

select u.id, u.name, ou.organisationId, ou.joinedat
from users u
  join (
     select distinct on (userid) userid, organisationid, joinedat 
     from organisations_users
     order by userid, joinedat desc
  ) ou on u.id = ou.userid 
where ou.organisationid = 2
这应该做到:

select u.id, u.name, ou.organisationId, ou.joinedat
from users u
  join (
     select userid, organisationid, joinedat, 
            max(joinedat) over (partition by userid) as last_join 
     from organisations_users
  ) ou on u.id = ou.userid and ou.joinedat = ou.last_join
where ou.organisationid = 2;
这假设一个用户不能同时在两个组织中。因此,最新的joinedat值标识用户的当前组织

如果用户可以同时加入多个组织,则需要将
max(joinedat)over(按用户ID划分)
更改为
max(joinedat)over(按用户ID划分,按组织ID划分)


另一个选项是使用
distinct on()
而不是窗口函数。通常,
distinct on()
解决方案的性能更好:

select u.id, u.name, ou.organisationId, ou.joinedat
from users u
  join (
     select distinct on (userid) userid, organisationid, joinedat 
     from organisations_users
     order by userid, joinedat desc
  ) ou on u.id = ou.userid 
where ou.organisationid = 2

备选方案,避免使用窗口函数和max()

选择u.id、u.name
,ou.organizationid
,ou.joinedAt
来自用户u
加入组织(用户)
ON u.id=ou.userId

和ou.joinedAt备选方案,避免使用窗口函数和max()

选择u.id、u.name
,ou.organizationid
,ou.joinedAt
来自用户u
加入组织(用户)
ON u.id=ou.userId

和ou.joined回答您的问题,并添加一些示例数据和基于该数据的预期输出。文本请,因为在
组织用户
表中有一个
加入的
列,但没有一个
退出的
列,所以每个曾经出现在组织
X
中的用户仍然会出现。@a_horse\u没有名字:就可以了now@wildplasser:没有,新机构取代旧机构ones@a_horse_with_no_name:使用样本数据和预期结果编辑。您的问题,并添加一些样本数据和基于该数据的预期输出。文本请,因为在
组织用户
表中有一个
加入的
列,但没有一个
退出的
列,所以每个曾经出现在组织
X
中的用户仍然会出现。@a_horse\u没有名字:就可以了now@wildplasser:没有,新机构取代旧机构ones@a_horse_with_no_name:使用样本数据和预期结果编辑。
SELECT u.id, u.name
        , ou.organisationId
        , ou.joinedAt
FROM users u
JOIN organisations_users ou
        ON u.id = ou.userId
        AND ou.joinedAt <= now()
        AND NOT EXISTS ( -- suppress all but the latest
                SELECT * FROM organisations_users nx
                WHERE nx.userId = ou.userId
                AND nx.organisationId <> ou.organisationId
                AND nx.joinedAt <= now()
                AND nx.joinedAt > ou.joinedAt
                )
WHERE ou.organisationId = 2
        ;