MySQL: IS NULL in joined tables - mysql

I'm having some difficulty with my JOIN and IS NULL..
Basically what I want to do is find all members who are not apart of certain group category ID's that I specify.
SELECT m.* FROM elvanto_members AS m
LEFT JOIN elvanto_groups AS g ON g.deleted = 0
LEFT JOIN elvanto_groups_categories AS gc ON gc.group_id = g.id AND (gc.category_id = '1' OR gc.category_id = '2')
WHERE gr.id IS NULL
Some members aren't apart of any group categories at all which is why I've made it a LEFT JOIN.
Am I making sense? Do you have any idea how to fix this?

Try this:
SELECT m.* FROM elvanto_members AS m
WHERE
not exists
(
SELECT 1 FROM
elvanto_groups AS g
INNER JOIN elvanto_groups_categories AS gc ON
gc.group_id = g.id
WHERE
gc.category_id IN ('1','2') AND
g.id = m.group_id AND
g.deleted = 0
)

SELECT m.*
FROM elvanto_members AS m
LEFT JOIN elvanto_groups AS g ON g.id = m.group_id AND g.deleted = 0
LEFT JOIN elvanto_groups_categories AS gc ON gc.group_id = g.id
AND gc.category_id IN ('1','2')
WHERE gc.group_id IS NULL
GROUP BY m.*
I filled in on spec what was missing in the question.
Is category_id really a string type? I would expect it to be numeric. Then this expression should be:
AND gc.category_id IN (1,2)

Related

mysql count from joins using 3 tables

i'm trying to build a chat application, in which i have these four tables
chat --id,group_id,body,time_posted[timestamp]
chat_groups --establish id,name for a group
users_groups --link users to a group, also define if user stared this group FIELDS::user_id,group_id,stared[bool]
wall_visit --user_id,group_id,last_visit[timestamp]
the idea is every users join a group, and they post to it in chat.
chat_groups table is just for defining the room, while users_groups is for setting access of members to this group.
wall_visit table is a table that store specific user last time accessed specific group (since its many to many u know..)
now what im trying to establish is to get in one query,
the chat_groups the user in relation with
the count of messages posted to this group since user last login (from settings)
the count of members in this group
the group name
:)
i have been trying to hours now :( best i could come up with
SELECT w.last_visit,access.stared,cg.user_id,u.fullname as username,cg.name as group_name ,cgu.count_members,c.count_msgs,c.time_posted
FROM `chat_groups`cg
inner join chat_groups_users access on (access.group_id = cg.id and access.user_id = ?)
left outer join users u on u.id = cg.user_id
left join wall_visit w on w.group_id = cg.id
left join (select count(*) as count_members,group_id from group_users group by group_id) cgu on cgu.group_id = cg.id
left join (SELECT count(wv.id) as count_msgs,c.group_id,c.time_posted FROM chats c
left outer join `wall_visit` wv on (wv.group_id is not null and c.group_id = wv.group_id and c.time_posted > wv.last_visit)
group by c.group_id) c on c.group_id = cg.id
where cg.user_id = 1
this query is working ..ehh, my main problem is with the count of the messages in the group since last_visit.
what is the best methode to get message_count to work :( ??
can this query be optimized more?
Thanks SO community :)
My 2nd attempt
SELECT w.last_visit,access.stared,cg.user_id,u.fullname as username,cg.with_id,uu.fullname as with_name,cg.name as group_name ,cgu.count_members,c.count_msgs,c.time_posted
FROM `chat_groups`cg
inner join chat_groups_users access on (access.group_id = cg.id and access.user_id = 1)
left outer join users u on u.id = cg.user_id
left join wall_visit w on w.chat_id = cg.id
left outer join users uu on uu.id = cg.with_id
left join (select count(*) as count_members,group_id from chat_groups_users group by group_id) cgu on cgu.group_id = cg.id
left join (
SELECT group_id,count(c.id) as count_msgs,time_posted FROM `chats` c inner join wall_Visit wv on wv.chat_id = c.group_id where c.id > wv.last_visit group by c.group_id
) c on c.group_id = cg.id
where cg.user_id = 1
this should fix you count message problem
SELECT
`cg`.`user_id`, `cg`.`with_id`, `cg`.`name` AS `group_name`,
`access`.`stared`,
`u`.`fullname` AS `username`,
`w`.`last_visit`,
`uu`.`fullname` AS `with_name`,
`cgu`.`count_members`,
`c`.`count_msgs`, `c`.`time_posted`
FROM `chat_groups` AS `cg`
INNER JOIN `chat_groups_users` AS `access`
ON (`access`.`group_id` = `cg`.`id` AND `access`.`user_id` = `cg`.`user_id`)
LEFT OUTER JOIN `users` AS `u`
ON (`u`.`id` = `cg`.`user_id`)
LEFT JOIN `wall_visit` AS `w`
ON (`w`.`chat_id` = `cg`.`id`)
LEFT OUTER JOIN `users` AS `uu`
ON (`uu`.`id` = `cg`.`with_id`)
LEFT JOIN (
SELECT COUNT(*) AS `count_members`, `group_id`
FROM `chat_groups_users`
GROUP BY
`group_id`
) AS `cgu`
ON (`cgu`.`group_id` = `cg`.`id`)
LEFT JOIN (
SELECT count(`c`.`id`) AS `count_msgs`, `c`.`time_posted`
FROM `chats` AS `c`
INNER JOIN `wall_visit` AS `wv`
ON (`wv`.`chat_id` = `c`.`group_id`)
WHERE
`c`.`time_posted` > `wv`.`last_visit`
GROUP BY
`c`.`group_id`
) AS `c`
ON (`c`.`group_id` = `cg`.`id`)
WHERE `cg`.`user_id` = 1
otherwise u have to setup a fiddle

About Mysql join case when error

select t.* FROM user_tq t join
CASE when t.blogid = 0 then user_dp ELSE user_blog END b
on t.uid = b.uid where ***;
I want to join different table according to blogid, when blogid is 0, join user_dp, else join user_blog.But it returns 1064 error.
How to solve this problem?
You can do this with left join and filter the right result by COALESCE
select t.*
FROM user_tq t
left join user_dp ud on t.blogid = 0 and t.uid = ud.uid
left join user_blog ub on t.blogid != 0 and t.uid = ub.uid
where
COALESCE(ud.uid, ub.uid) IS NOT NULL and
***;
For more info refer : MySQL query where JOIN depends on CASE
If you are trying to inner join to filter data on condition then;
select * from (
select t.*
FROM user_tq t
join user_dp ud on t.blogid = 0 and t.uid = ud.uid
union all
select t.*
FROM user_tq t
join user_blog ub on t.blogid != 0 and t.uid = ub.uid
) as x
where ****;
USE:
select * FROM users t
left join user_role r ON t.user_id = 0 AND r.user_id = t.user_id
left join product_category c ON t.user_id != 0 AND c.user_id = t.user_id
WHERE COALESCE(r.user_id, c.user_id) IS NOT NULL
WHERE ***;
Replace users, user_role and product_category with your tables.
The other answers posted here are the correct solutions.
I'll answer the "Why do I get 1064" for you.
The syntax you've written is invalid. You cannot "conditionally" join to a table like this.
What you can do is LEFT JOIN - which as opposed to [INNER] JOIN means "return NULL for all fields on this table if no record matches the join condition".
There's lots on the Internet about LEFT vs INNER joins, and MySQL's website documents the COALESCE function very well.
Have a play and a read, you'll figure it out why the other solutions work.
Upon reflection, I felt this could benefit from some additional explanation.
See this SQLFiddle: http://sqlfiddle.com/#!9/043b7/6

Foreach non-unique rows to obtain a related key

Can such SELECTion be made? Based only on QTZ_USERS UUID can I "foreach" all memberships with GROUP_ID's to find the GROUP_ID with the highest prority?
How can I approach that?
Assuming you want details from all the tables then join them together and to a sub query to get the latest priority for each user.
Something like the following (although select the actual columns you want rather than use SELECT *).
SELECT *
FROM QTZ_USERS u
INNER JOIN MEMBERSHIPS m
ON u.UUID = m.UUID
INNER JOIN GROUPS g
ON m.GROUP_ID = g.GROUP_ID
INNER JOIN
(
SELECT m.UUID, MAX(g.PRIORITY) AS max_priority
FROM MEMBERSHIPS m
INNER JOIN GROUPS g
ON m.GROUP_ID = g.GROUP_ID
GROUP BY m.UUID
) sub0
ON m.UUID = sub0.UUID
AND g.PRIORITY = sub0.max_priority
Principially you do this with GROUP BY and aggregate functions, here MAX.
SELECT
m.UUID,
MAX(g.PRIORITY)
FROM
memberships m
INNER JOIN
groups g
ON
m.GROUP_ID = g.GROUP_ID
GROUP BY
m.UUID;
If you need the GROUP_ID, then you can use a subselect
SELECT
m.UUID,
g.GROUP_ID
FROM
memberships m
INNER JOIN
groups g
ON
m.group_id = g.group_id
WHERE
g.priority = (
SELECT
MAX(g2.priority)
FROM
groups g2
WHERE
g.group_id = g2.group_id
GROUP BY
g2.group_id
);

complex join query in mysql

Hy everyone,
I really need your help. I have to obtain the list (distinct) of all users who :
- have a live checkin ( checkins.ctype = 'live' ) in a match
- where they favorite team ( see fanusers_teams )
- won by 3 ore more goals difference.
The favorite team, could be info_matches.team_id1 OR info_matches.team_id2 or even both.
Here is a small design for the involved tables :
What I've tried, works 80% (so it doesn't :( ) because it returns some users correct (they fav. teams by 3+ goals diff) , but also returns users which don't have a fav. team in the situation. I think that they are returned because they've made a live checkin for a match where one team or the other has won by a 3+ goals diff.
Here is my query :
SELECT DISTINCT
f.id
FROM
fanusers f
LEFT JOIN
checkins c ON f.id = c.fanuser_id
LEFT JOIN
info_matches m ON m.id = c.match_id
WHERE
c.ctype = 'live' AND
(
m.team_id1 IN(
SELECT DISTINCT
m1.team_id1
FROM
info_matches m1
RIGHT JOIN
fanusers_teams ft ON m1.team_id1 = ft.team_id
RIGHT JOIN
fanusers f ON f.id = ft.fanuser_id
WHERE
m1.pointsteam1 - m1.pointsteam2 >= 3
)
OR
m.team_id2 IN(
SELECT DISTINCT
m2.team_id2
FROM
info_matches m2
RIGHT JOIN
fanusers_teams ft ON m2.team_id2 = ft.team_id
RIGHT JOIN
fanusers f ON f.id = ft.fanuser_id
WHERE
m2.pointsteam2 - m2.pointsteam1 >= 3
)
)
I would appreciate also a small explanation regarding what am I doing wrong, if there is someone who succeed to solve this query.
Thanks.
Something like this should work:
SELECT DISTINCT f.id
FROM fanusers f
JOIN checkins c
ON f.id = c.fanuser_id
JOIN fanusers_teams ft
ON f.id = ft.fanuser_id
JOIN info_matches m
ON m.id = c.match_id
AND
(
(ft.team_id = m.team_id1 AND pointsteam1 - pointsteam2 >= 3)
OR
(ft.team_id = m.team_id2 AND pointsteam2 - pointsteam1 >= 3)
)
WHERE c.ctype = 'live'
I've found also a way to solve the query, but not so nice as Tom did it.
My way :
SELECT DISTINCT
f.id AS user_id
FROM
fanusers f
LEFT JOIN
checkins c ON f.id = c.fanuser_id
LEFT JOIN
info_matches m ON m.id = c.match_id
WHERE
c.ctype = 'live'
AND
m.matchisfinished = 1
AND
c.fanuser_id NOT IN ( SELECT DISTINCT
f1.id
FROM
fanusers f1
LEFT JOIN
fanusers_stickers fs
ON f1.id = fs.fanuser_id
WHERE
fs.sticker_id = 35
)
AND
(
( m.team_id1 IN ( SELECT DISTINCT
ft.team_id
FROM
fanusers_teams ft
INNER JOIN
checkins c1
ON
ft.fanuser_id = c1.fanuser_id
WHERE
f.id = c1.fanuser_id
)
AND
m.pointsteam1-m.pointsteam2>=3
)
OR
(
m.team_id2 IN ( SELECT DISTINCT
ft.team_id
FROM
fanusers_teams ft
INNER JOIN
checkins c1
ON
ft.fanuser_id = c1.fanuser_id
WHERE
f.id = c1.fanuser_id
)
AND
m.pointsteam2-m.pointsteam1>=3
)
)
So for the moment, even if I'm happy that I've solved the query by myself, I will use Tom's query :).

only returning records when s.id = u.summary_id

select
s.id, s.description, s.improvement, s.previous_year_id,
s.current_year_id, s.first_name, s.last_name, s.username,
s.finding, s.action, s.share, s.learned, s.timestamp,
d.title as department_title,
group_concat(g.title SEPARATOR \' | \') as strategic_goals,
y1.year as current_year_title, y2.year as previous_year_title,
u.summary_id, u.file_name as file_name
from
summary s, year y1, year y2, strategic_goal_entries sge,
goal g, department d, uploads u
where
s.id = sge.summary_id
and
s.current_year_id = y1.id
and
s.previous_year_id = y2.id
and
sge.goal_id = g.id
and
s.id = u.summary_id
and
s.department_id = d.id
and
s.department_id = '4'
group by
s.id
This only returns records from the summary table that has a relating record in the uploads table (s.id = uploads.summary_id) that contain a value within the uploads.summary_id field
I want to return all records, whether or not it has a file associated with it.
Any help is appreciated.
Suggest refactoring this SQL query to use ANSI joins. To achive your goal, you'd want a LEFT JOIN instead:
SELECT /*your columns*/
from summary s
INNER JOIN year y1 ON s.current_year_id = y1.id
INNER JOIN year y2 ON s.previous_year_id = y2.id
INNER JOIN strategic_goal_entries sge ON s.id = sge.summary_id
INNER JOIN goal g ON sge.goal_id = g.id
INNER JOIN department d ON s.department_id = d.id
LEFT JOIN uploads u ON s.id = u.summary_id
WHERE s.department_id = '4'
group by s.id