我需要连接 2 个表才能根据第一个表中的有效行获取第二个表中的最新/最新更新。
下面的代码是示例。
表 1:注册用户
此表包含在系统中注册的用户列表。当用户注册时,它将被添加到此表中。用户使用名称和注册时间进行注册。用户可以从系统中取消注册。完成此操作后,取消注册列将更新为删除用户的时间。如果此值为 NULL,则表示用户仍处于注册状态。
CREATE TABLE users (
entry_idx SERIAL PRIMARY KEY,
name TEXT NOT NULL,
reg_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
dereg_time TIMESTAMP WITH TIME ZONE DEFAULT NULL
);
表 2:用户更新
此表包含有关用户的更新。每次用户更改属性(示例位置)时,更改都会存储在此表中。无需删除任何更新,因为需要在表中保留历史记录。
CREATE TABLE user_updates (
entry_idx SERIAL PRIMARY KEY,
name TEXT NOT NULL,
position INTEGER NOT NULL,
time TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
所需输出
因此,鉴于上述信息,我需要获取一个仅包含当前注册用户的最新更新的新表。
测试数据
以下数据可用作上述表的测试数据:
-- Register 3 users
INSERT INTO users(name) VALUES ('Person1');
INSERT INTO users(name) VALUES ('Person2');
INSERT INTO users(name) VALUES ('Person3');
-- Add some updates for all users
INSERT INTO user_updates(name, position) VALUES ('Person1', 0);
INSERT INTO user_updates(name, position) VALUES ('Person1', 1);
INSERT INTO user_updates(name, position) VALUES ('Person1', 2);
INSERT INTO user_updates(name, position) VALUES ('Person2', 1);
INSERT INTO user_updates(name, position) VALUES ('Person3', 1);
-- Unregister the 2nd user
UPDATE users SET dereg_time = NOW() WHERE name = 'Person2';
从上面,我想要人员 1 和人员 3 的最新更新。
失败的尝试
我尝试过使用连接和其他方法,但结果不是我想要的。这个问题与这里提出的问题几乎相同。我已经在答案 1 中使用了解决方案,它确实给出了正确的答案,但在我的系统中获得答案需要很长时间。
根据上面的链接,我创建了以下"有效"查询:
SELECT
t1.*
, t2.*
FROM
users t1
JOIN (
SELECT
t.*,
row_number()
OVER (
PARTITION BY
t.name
ORDER BY t.entry_idx DESC
) rn
FROM user_updates t
) t2
ON
t1.name = t2.name
AND
t2.rn = 1
WHERE
t1.dereg_time IS NULL;
问题上述查询的问题在于需要很长时间才能完成。表 1 包含一小部分用户,而表 2 包含大量更新。我认为查询在处理 2 个表的方式上可能效率低下(基于我对查询的有限理解)。根据 pgAdmin 的解释,它在与注册表连接之前对更新 1st 进行了大量排序和聚合。
问题
如何制定查询以高效快速地获取注册用户的最新更新?
PostgreSQL对这种类型的查询有一个特殊的distinct on
语法:
select distinct on(t1.name)
--it's better to specify columns explicitly, * just for example
t1.*, t2.*
from users as t1
left outer join user_updates as t2 on t2.name = t1.name
where t1.dereg_time is null
order by t1.name, t2.entry_idx desc
SQL 小提琴演示
您可以尝试一下,但对我来说,您的查询也应该可以正常工作。
我正在使用 q1 来获取每个用户的最新更新。然后与用户联接以删除已取消注册的条目。然后加入 q2 以获取其余user_update字段。
select users.*,q2.* from users
join
(select name,max(time) t from user_updates group by name) q1
on users.name=q1.name
join user_updates q2 on q1.t=q2.time and q1.name=q2.name
where
users.dereg_time is null
(我还没有测试过,编辑了一些东西)