Reputation: 409
There are 4 tables.
My objective is to get a list of all those items where item_owner = user_id ( say 123 ) or user_id belongs to a group with which the item is shared.
A basic query implementation to retrieve all items shared with a group to which a particular user_id belongs would be
select i.item_id from items i
left outer join share on share.item_id = i.item_id
left outer join users on users.grp_id = share.grp_id
left outer join groups on groups.grp_id = share.grp_id
where users.usr_ref = user_id
And to include all other elements of which user_id is the owner, i did something like
select * from items where owner = user_id or item_id in (
select i.item_id from items i
left outer join share on share.item_id = i.item_id
left outer join users on users.grp_id = share.grp_id
left outer join groups on groups.grp_id = share.grp_id
where users.usr_ref = user_id )
which i suppose is a very bad implementation as the item_id needs to be searched everytime in the array obtained from the joins. How can i improve my sql statement.
Also is there any other way in which i can redesign my table structure so that i can implement the query in some other way ?
Thanx in advance.
Upvotes: 3
Views: 126
Reputation: 12672
I think this will work.
select i.item_id from items i
inner join share on share.item_id = i.item_id
inner join users on users.grp_id = share.grp_id
inner join groups on groups.grp_id = share.grp_id
where (users.usr_ref = @user_id or @user_id is null) and (i.item_id = @item_id or @item_id is null)
I'm guessing that you will always pass one paramether or the other one, not both, so the other one (the non-passed) will be null
also, why are you using left join? use inner instead, because you don't want null fields
Upvotes: 0
Reputation: 62841
Perhaps I'm not understanding your question, but can you not just use OR
with your first query:
select i.item_id from items i
left outer join share on share.item_id = i.item_id
left outer join users on users.grp_id = share.grp_id
left outer join groups on groups.grp_id = share.grp_id
where i.item_owner = @user_id or users.usr_ref = @user_id
Upvotes: 0
Reputation: 263713
You need INNER JOIN
in this case because you need to get an item that has connection on all tables. Your current query uses LEFT JOIN
that is why even an item that has not associated on any user will be shown on the list. Give this a try,
SELECT DISTINCT a.*
FROM items a
INNER JOIN `share` b
ON a.item_ID = b.item_ID
INNER JOIN groups c
ON b.grp_ID = c.grp_ID
INNER JOIN users d
ON c.grp_ID = d.grp_ID
WHERE d.usr_ref = user_ID
To further gain more knowledge about joins, kindly visit the link below:
Upvotes: 2