Aim:
- List all unique events
- Have a dedicated column called
reviewedbased on the current user - Events must be listed event if current user is not invited
Possible cases:
- User is invited
- User is not invited
An event is reviewed by each "confirmed" user (not all of the invitations are confirmed) Conditions to be "reviewed":
- review exists
- there is at least one attachments linked to this review
I have 4 tables in Postgresql 14.7.
- events
- invitations (1-1/user/event)
- review (0-1/invitation)
- attachments (0-n/review)
Here they are:
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
);
I got an SQL view for that but it is wrong because reviewed did not match the current user invitation (it is random, based on invitation creation).
Here is current code I have
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;)
I've read Select first row in each GROUP BY group? dozens of times but I'm not sure it fits on my case
In my mind, this view was "temporary" until I scope the results with the current user invitations.
I have part of the solution using 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;)
Then I LEFT OUTER JOIN on manual_invitation_id when I want to scope with the current user, combining it with WHERE rn=1.
But rn can be any number, not only one. So scope is not working.
I don't even know if it's possible in a single query. I want to avoid sub queries since it's one of the most used in the app. Additionally, it's inside a Rails app so I'm not sure subqueries can be handled that easily with ActiveRecord.
List all events, with a flag
reviewedfor the current user:An
EXISTSsubquery expression is probably fastest.Don't use a generic
VIEWfor this if you want the result for the current user. Use the given query, or wrap it into a set-returningFUNCTION. Example: