I have a selection and I wanted to search a column of a table by left join only if the User is enabled with the pre condition to essar search as a condition that adds tables I was a little confused, I do not know if I separate searches or I do everything at once ....
He says it's for me to look at the mysql system, but I see so
if .condition... then ... end if;
My code
select user. * from
u user
if (u.visible == 1,
left join houseUser hu on u.id = h.id_user
left join h house on hu.id_house = h.id_house
)
where
u.age> 30
if visible add that code to can see in what house the user is.
You can just incorporate the condition into the on clauses:
select u.*, hu.*, h.*
from user u left join
houseUser hu
on u.id = h.id_user and u.visible = 1 left join
h house
on hu.id_house = h.id_house and u.visible = 1
where u.age > 30;
The columns will come back, but they will be NULL when visible is not 1.
Related
I have three tables:
Users and companies can add feeds. The flag columns means
0 = user
1 = company
How can I perform this SQL query correctly? Thanks in advance for your help!
SELECT
feeds.feeds_id,
feeds.title
IF feeds.flag = 0
FROM user
INNER JOIN
feeds.user_or_company = user.user_id
ELSEif feeds.flag = 1
INNER JOIN
feeds.user_or_company = company.company_id
One way to solve this is to LEFT JOIN to both user and company tables and then select the appropriate name value based on feeds.flag:
SELECT f.feeds_id, f.title,
CASE f.flag WHEN 0 THEN u.name ELSE c.name END AS name
FROM feeds f
LEFT JOIN user u ON u.user_id = f.user_or_company
LEFT JOIN company c ON c.company_id = f.user_or_company
Output (for your sample data)
feeds_id title name
2 This title added twice by user User-1
3 This title added by company Company-2
1 This title added by user User-3
Demo on dbfiddle
I have 4 tables user, posts, follows, notifications. The posts table has a field called privacy in which a value of 1 means "anyone can see" and 2 means "only friends can see".
My notifications table looks like this:
id user_id tonotify_id notification post_id
1 2 3 --- 1
2 3 2 --- 2
3 2 4 --- 3
And my follows table looks like this:
id user_id tofollow_id status fstatus
1 1 2 1 1
2 1 3 1 1
The field fstatus value of 1 means that they are also friends.
Now I am trying to get all notifications sent out by people who a certain user is following (lets say a user with id 1). Assuming 1 is following user 2 and 3, I need to get all notifications from the above table. However, before this I need to make sure that the post (posted by the users in the tonotify_id column) is available. That is, I need to check the privacy setting. I have the following code:
SELECT
u.username AS sender,
ux.username AS receiver,
p.id
FROM notifications n
JOIN follows f ON (n.user_id = f.tofollow_id)
JOIN follows fr ON (n.tonotify_id = fr.tofollow_id)
JOIN user u ON (u.id = n.user_id)
JOIN user ux ON (ux.id = n.tonotify_id)
LEFT JOIN posts p ON (n.posts_id = p.id)
WHERE f.user_id = 1
AND fr.user_id = 1
AND f.status = 1
AND p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1)
ORDER BY n.id DESC
It seems to be working except for one glitch. Since user 1 is not following user 4 all notifications aimed at 4, even if the posts are public don't show up. This my guess has to do with JOIN follows fr ON (n.tonotify_id = fr.tofollow_id) because, since the user 1 hasn't followed 4, there are no rows matching this join. Any suggestions to solving this?
I did try [the outer join], but the output is the same.
When you use an outer join, and then use one of the "outer" columns in an equality check in the WHERE clause, you convert your outer join to an inner join. This is because your condition that checks post's privacy requires the post to be there:
AND p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1)
When an outer join is about to produce a row that corresponds to a notification without a post, it would check the above condition. Since the post is not there, p.privacy would evaluate to NULL, "contaminating" both sides of the OR, and eventually making the whole condition evaluate to false.
Moving this condition into the ON condition of the join will fix the problem:
SELECT
u.username AS sender,
ux.username AS receiver,
p.id
FROM notifications n
JOIN follows f ON (n.user_id = f.tofollow_id)
JOIN follows fr ON (n.tonotify_id = fr.tofollow_id)
JOIN user u ON (u.id = n.user_id)
JOIN user ux ON (ux.id = n.tonotify_id)
LEFT JOIN posts p ON (n.posts_id = p.id)
AND (p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1))
WHERE f.user_id = 1
AND fr.user_id = 1
AND f.status = 1
ORDER BY n.id DESC
Another way to fix this would be adding an IS NULL condition to your OR, like this:
SELECT
u.username AS sender,
ux.username AS receiver,
p.id
FROM notifications n
JOIN follows f ON (n.user_id = f.tofollow_id)
JOIN follows fr ON (n.tonotify_id = fr.tofollow_id)
JOIN user u ON (u.id = n.user_id)
JOIN user ux ON (ux.id = n.tonotify_id)
LEFT JOIN posts p ON (n.posts_id = p.id)
WHERE f.user_id = 1
AND fr.user_id = 1
AND f.status = 1
AND (p.privacy IS NULL OR p.privacy = 1 OR (p.privacy = 2 AND fr.fstatus = 1))
ORDER BY n.id DESC
You need to use an outer join such as LEFT JOIN instead of an inner join using just JOIN. An outer join will always return rows from one "side" (which is why it is called LEFT [OUTER] JOIN and RIGHT [OUTER] JOIN) even if the other "side" does not match anything.
I have this query:
SELECT
e.*, u.name AS event_creator_name
FROM `edu_events` e
LEFT JOIN `edu_users` u
ON u.user_id = e.event_creator
INNER JOIN `edu_event_participants`
ON participant_event = e.event_id && participant_user = 1
WHERE
MONTH(e.event_date_start) = 6
AND YEAR(e.event_date_start) = 2013
It works perfect, however, I only want to do the INNER JOIN if the value: e.event_type equals 1. If not, it should ignore the INNER JOIN.
I have tried for some time to figure it out, but the solutions seems difficult to implment for my proposes (as it is only for select/specific values).
I'm thinking about something like:
SELECT
e.*, u.name AS event_creator_name
FROM `edu_events` e
LEFT JOIN `edu_users` u ON u.user_id = e.event_creator
if(e.event_type == 1) {
INNER JOIN `edu_event_participants` ON participant_event = e.event_id && participant_user = 1
}
WHERE MONTH(e.event_date_start) = 6
AND YEAR(e.event_date_start) = 2013
I have edited the below following further feedback from #Matthias
-- This will get all events for a given user plus all globals
SELECT
e.*,
u.name AS event_creator_name
FROM `edu_users` u
-- in the events
INNER JOIN `edu_events` e
ON (
-- Get all the ones that the user is participant
e.event_creator = u.user_id
-- Or where event_type is 1
OR
e.event_type = 1
)
AND e.event_date_start BETWEEN DATE('2013-06-01') AND DATE('2013-07-01')
-- Add in event participants even though it doesn't seem to be used?
INNER JOIN `edu_event_participants` AS eep
ON eep.participant_event = e.event_id
AND eep.participant_user = 1
-- Add the user ID into the WHERE
WHERE u.user_id = 1;
This just might not make too much sence as it feels as though edu_event_participants has too much information in. event_creator should really be stored against the event itself, and then event_participants just containing an event id, user id, and user type.
If you are looking to get all users on an event, it may be better to do a seperate query for that event to select all users based off an event_id
The note on your use of MONTH() and YEAR(). This will trigger a table scan, as MySQL will need to apply the MONTH() and YEAR() functions to all rows to determine which match that WHERE statement. If you instead calculate the upper and lower limits (i.e. 2013-06-01 00:00:00 <= e.event_date_start < 2013-07-01 00:00:00) then MySQL can use a far more efficient range scan on an index (assuming one exists on e.event_date_start)
If I understand correctly you only want the results where there is an entry on edu_event_participants with the same event_id and participant_user = 1 but only if event_type = 1, but you don't really want to get any information from the edu_event_participants table. If that is the case:
SELECT
e.*, u.name AS event_creator_name
FROM `edu_events` e
LEFT JOIN `edu_users` u
ON u.user_id = e.event_creator
WHERE
-- as Simon at mso.net suggested
WHERE e.event_date_start BETWEEN DATE('2013-06-01') AND DATE('2013-07-01')
-- MONTH(e.event_date_start) = 6
-- AND YEAR(e.event_date_start) = 2013
AND (
-- either event is public
e.event_type = 1 or
-- or the user is in the participants table
exists
(select 1 from `edu_event_participants`
where participant_event = e.event_id
AND participant_user = 1)
)
Maybe what you're after is displaying the left table value even if there's no matching data from right table? On that case you can use outer join like so:
LEFT OUTER JOIN `edu_event_participants` ON participant_event = e.event_id && participant_user = 1 AND e.event_type = 1
I have several tables that I am trying to get some data out of, and I am very close, but cannot quite close the deal.
I have the following tables:
EVENT
USER
FRIEND
USER__FRIEND
EVENT__INVITATION
USER and FRIEND are linked via the USER__FRIEND table (which contains a USER_ID and a FRIEND_ID field)
EVENT__INVITATION links an EVENT with a FRIEND (it has EVENT_ID and INVITEE_ID)
I am trying to get all EVENTS where:
I am the EVENT creator ($myUserID = EVENT.CREATOR_ID)
or I am invited to the event ($myUserID = EVENT__INVITATION.INVITEE_ID)
or one of my FRIENDs is the creator of the EVENT ($myUserID = USER__FRIEND.USER_ID AND EVENT.CREATOR_ID IN (list of my FRIENDs))
or one of my FRIENDs is invited to the EVENT ($myUserID = USER__FRIEND.USER_ID AND EVENT__INVITATION.INVITEE_ID IN (list of my FRIENDs))
There are some other WHERE conditions around other parameters, but I think I can sort those out on my own.
Right now the only way I could get this to work was with a UNION, which I think must be a cop-out, and if I had better chops I could get around using it.
So, the question is, can this be done with a single, inexpensive query that does not use a UNION?
Here is what I have so far, which accomplishes everything except the EVENTs that my FRIENDs are invited to (23 is the passed in userID in this case):
SELECT e.*
FROM event e
LEFT JOIN event__invitation ei ON ei.event_id = e.id
LEFT JOIN user__friend uf ON uf.friend_id = ei.invitee_id
LEFT JOIN friend f ON f.id = uf.friend_id
WHERE (ei.invitee_id = 23 OR e.creator_id = 23 OR uf.user_id = 23 OR f.user_id = e.creator_id)
AND e.start_time >= 1348000000
and this is the query with the UNION:
SELECT e.* FROM event e
INNER JOIN event__invitation ei ON ei.event_id = e.id
INNER JOIN user__friend uf ON uf.friend_id = ei.invitee_id
WHERE (e.creator_id = 23 OR ei.invitee_id = 23 OR uf.user_id = 23)
UNION
SELECT e1.* FROM event e1
WHERE e1.creator_id IN (
SELECT f1.user_id FROM friend f1
INNER JOIN user__friend uf1 ON uf1.friend_id = f1.id
WHERE uf1.user_id = 23
AND f1.user_id IS NOT NULL
);
There is more to the query that makes the use of the UNION undesireable. I have a complex trig calculation that I am doing in the main select, and am ordering the results by that value. I think may mess up the result set.
Thanks for any help!!
How about the following:
-- take only distinct events
SELECT DISTINCT e.*
-- start with the event
FROM event e
-- expand to include all invitees and their user_friend info
LEFT JOIN event__invitation ei
ON ei.event_id = e.id
LEFT JOIN user__friend invitee
ON invitee.friend_id = ei.invitee_id
-- now we join again to user_friend to get the friends of the invitees/the creator
LEFT JOIN user__friend invitedFriend
ON invitedFriend.user_id = invitee.user_id
OR invitedFriend.user_id = e.creator_id
-- finally we match on whether any of these friends of friends are myself
LEFT JOIN friend myselfAsAFriend
ON myselfAsAFriend.id = invitedFriend.friendId
AND myselfAsAFriend.userID = 23
WHERE
(
-- (1) I am the creator of the event
e.creator_id = 23
-- (2) I am invited to the event
OR invitee.user_id = 23
-- (3 and 4) for this join to match a friend of mine must be invited or the creator
OR myselfAsAFriend.id IS NOT NULL
)
AND e.start_time >= 1348000000
I'm not very good at query tuning presently, so I would just give something like this a try and let the optimiser to put its effort in figuring out the best way of getting the results:
SELECT DISTINCT e.*
FROM event e
INNER JOIN event__invitation ei ON ei.event_id = e.id
INNER JOIN (
SELECT friend_id
FROM user__friend
WHERE user_id = $myUserID
UNION ALL
SELECT $myUserID
) u ON u.friend_id IN (e.creator_id, ei.invitee_id)
;
If this doesn't prove efficient enough, you could always go with something like #ChaseMedallion's suggestion, as it may indeed turn out a better one for your case.
am having a problem constructing a query
here is simplified tables structure
3 tables
Event [Event_id , Event_name]
Event_files [Event_id(FK) , File_id(FK)]
Uploaded_Files[File_id , File_type, File_path]
we mainly have 2 file types
image = 2
document = 4
what am trying to do is to get the events along with their images (if they have an image )
am trying to do this with this Query
select e.id, e.name,uf.id as file_id,uf.path
from event e
left join event_file ef on ef.event_id = e.id
left join uploaded_file uf ON ef.file_id = uf.id
i know that i need to apply a condition but each time i do in the where or ON there is always problem with the Query
for example if i apply :
left join uploaded_file uf ON ef.file_id = uf.id AND (uf.type = 2 )
it will still return 2 records for the events that has both image and file one of them with file_path null .
on the other hand if i do the following :
where (uf.id is null OR (uf.id is not null AND uf.type=2))
the events with only files and no image will not be returned any more
is there is solution please ?
thanks in advance
SELECT e.id, e.name, f.file_id AS file_id, f.path
FROM event e
LEFT JOIN
(
SELECT ef.event_id, uf.id AS file_id, uf.path
FROM event_file ef
INNER JOIN uploaded_file uf ON ef.file_id = uf.id AND uf.type = 2
) f ON f.event_id = e.id
This should do (untested.)
The reason you're getting the empty record is because you only specify the uf.type condition on the uploaded_file table, which imposes nothing on the left join for event_file.