提问人:brcebn 提问时间:11/14/2023 最后编辑:brcebn 更新时间:11/14/2023 访问量:90
SQL 视图,其计数取决于当前用户
SQL view with count depending on current user
问:
目的:
- 列出所有唯一身份事件
- 有一个基于当前用户调用的专用列
reviewed
- 如果未邀请当前用户,则必须列出事件
可能的情况:
- 用户被邀请
- 未邀请用户
每个“已确认”用户都会审核活动(并非所有邀请都已确认) “审查”条件:
- 存在审查
- 至少有一个附件链接到本综述
我在 Postgresql 14.7 中有 4 个表。
- 事件
- 邀请(1-1/用户/事件)
- 评论 (0-1/邀请)
- 附件 (0-N/review)
他们来了:
CREATE TABLE public.events (
id bigint NOT NULL,
name character varying NOT NULL,
start_at timestamp without time zone NOT NULL,
end_at timestamp without time zone NOT NULL
);
CREATE TABLE public.invitations (
id bigint NOT NULL,
status integer DEFAULT 0 NOT NULL,
user_id bigint NOT NULL,
event_id bigint NOT NULL,
);
CREATE TABLE public.reviews (
id bigint NOT NULL,
reviewable_id bigint NOT NULL,
reviewable_type character varying NOT NULL,
comment text
);
CREATE TABLE public.attachments (
id bigint NOT NULL,
attachable_id bigint NOT NULL,
attachable_type character varying NOT NULL
);
我得到了一个SQL视图,但它是错误的,因为它与当前用户邀请不匹配(它是随机的,基于邀请创建)。
这是我拥有的当前代码reviewed
CREATE OR REPLACE VIEW my_view AS
SELECT
((e.enable_review = true AND r.id IS NOT NULL AND count(a) > 0 ) OR e.enable_review = false) AS reviewed,
e.*
FROM events e
LEFT JOIN invitations i ON i.event_id = e.id
LEFT JOIN reviews r ON (r.reviewable_type = 'Invitation' AND r.reviewable_id = i.id)
LEFT JOIN attachments a ON (a.attachable_type = 'Review' AND a.attachable_id = r.id)
GROUP BY e.id, r.id;)
我已经阅读了 Select first row in each GROUP BY group? 几十遍了,但我不确定它是否适合我的情况
在我看来,这种观点是“暂时的”,直到我使用当前的用户邀请来限定结果的范围。
我有一部分解决方案使用row_number
CREATE OR REPLACE VIEW my_view AS
SELECT
((e.enable_review = true AND r.id IS NOT NULL AND count(a) > 0 ) OR e.enable_review = false) AS reviewed,
e.*,
row_number() OVER (PARTITION BY i.event_id ORDER BY i.id DESC) AS rn,
i.id as manual_invitation_id
FROM events e
LEFT JOIN invitations i ON i.event_id = e.id
LEFT JOIN reviews r ON (r.reviewable_type = 'Invitation' AND r.reviewable_id = i.id)
LEFT JOIN attachments a ON (a.attachable_type = 'Review' AND a.attachable_id = r.id)
GROUP BY e.id, i.id, r.id;)
然后,当我想确定当前用户的范围时,我会将其与 .
但可以是任何数字,而不仅仅是一个。所以范围不起作用。LEFT OUTER JOIN
manual_invitation_id
WHERE rn=1
rn
我什至不知道在单个查询中是否可能。我想避免子查询,因为它是应用程序中最常用的查询之一。此外,它位于 Rails 应用程序中,因此我不确定使用 ActiveRecord 可以轻松处理子查询。
答:
1赞
Erwin Brandstetter
11/14/2023
#1
列出所有事件,并带有当前用户的标志:reviewed
SELECT EXISTS (
SELECT
FROM invitations i
JOIN reviews r ON r.reviewable_id = i.id
JOIN attachments a ON a.attachable_id = r.id
WHERE i.user_id = $current_user_id -- ???
AND i.event_id = e.id
AND r.reviewable_type = 'Invitation'
AND a.attachable_type = 'Review'
) AS reviewed
, e.*
FROM events e;
EXISTS
子查询表达式可能是最快的。
如果您想要当前用户的结果,请不要为此使用泛型。使用给定的查询,或将其包装到返回集合的 FUNCTION
中。例:VIEW
评论
0赞
brcebn
11/14/2023
我想避免子查询。另外,在这里,我将限定当前用户被邀请的所有事件,但我想要所有这些事件。我在描述中添加了很多细节。这还不够清楚。🙂
0赞
Erwin Brandstetter
11/14/2023
没有理由避免.“subquery”只是另一个返回 .EXISTS
boolean
0赞
brcebn
11/14/2023
我害怕子查询的性能问题(我肯定错了)。是否有可能在视图中拥有它并且仍然具有动态性?$current_user_id
0赞
Erwin Brandstetter
11/14/2023
我给出这个查询是因为我希望它是最快的。如果您希望为当前用户自定义结果,则一开始就使用 A 是错误的工具。VIEW
1赞
Erwin Brandstetter
11/15/2023
优秀的手册。以及 SO 和 dba.SE 上值得信赖的用户的回答。性能优化是棘手的,需要知识、经验和科学思维。一路顺风!:)
评论
reviewed