MySQL LEFT JOIN Multiple Conditions - mysql

I have two tables: A and B linked by "group_id".
2 variables I'm using: $keyword, $_SESSION['user_id']
A
group_id
keyword
B
id
group_id
user_id
I want to be able to select all the groups that this user is not in based on a keyword search.
Therefore the goal is to SELECT all the rows in A WHERE the user_id!={$_SESSION['user_id'} for the corresponding group_id in B AND like the keyword.
this is what I tried:
SELECT a.*
FROM a
LEFT JOIN b ON a.group_id=b.group_id
WHERE a.keyword LIKE '%".$keyword."%'
AND b.user_id!=$_SESSION{['user_id']}
GROUP BY group_id
However, it does not find any rows (matches) unless I remove AND b.user_id!=$_SESSION{['user_id']} in which case it will also include groups the user is already in - which is not what I want.
Any help would be appreciated! Thanks

Just move the extra condition into the JOIN ON criteria, this way the existence of b is not required to return a result
SELECT a.* FROM a
LEFT JOIN b ON a.group_id=b.group_id AND b.user_id!=$_SESSION{['user_id']}
WHERE a.keyword LIKE '%".$keyword."%'
GROUP BY group_id

Correct answer is simply:
SELECT a.group_id
FROM a
LEFT JOIN b ON a.group_id=b.group_id and b.user_id = 4
where b.user_id is null
and a.keyword like '%keyword%'
Here we are checking user_id = 4 (your user id from the session). Since we have it in the join criteria, it will return null values for any row in table b that does not match the criteria - ie, any group that that user_id is NOT in.
From there, all we need to do is filter for the null values, and we have all the groups that your user is not in.
demo here

Above answers are correct. Another way to achieve this is;
SELECT a.group_id
FROM a
LEFT JOIN b ON (a.group_id, b.user_id) = (b.group_id, 4)
where b.user_id is null
and a.keyword like '%keyword%'
Complete Example

SELECT * FROM a WHERE a.group_id IN
(SELECT group_id FROM b WHERE b.user_id!=$_SESSION{'[user_id']} AND b.group_id = a.group_id)
WHERE a.keyword LIKE '%".$keyword."%';

Related

How to achiave this:MYSQL SELECT if true select a else select b?

I want to select user.* if chat.chat_type IS NULL, but if chat.chat_type = 1
I want to select group.*
SELECT
CASE
WHEN chat.chat_type IS NULL THEN user.*
WHEN chat.chat_type =1 THEN group.*
END,
x,y
FROM `chat` LEFT JOIN group ...
How I can achieve this?
The database design as described is not so good, because you have an ID in your chat table that can either be a user ID or a group ID. Thus you cannot have a constraint (foreign key) on this column, which makes it possible to put any value in there, i.e. even an ID that doesn't exist.
Anyway, with the design given, to get either user or group you outer join both tables on the conditions you already mentioned. Then use COALESCE to see whether you got a user or a group in the result row.
select c.from, coalesce(u.name, g.name) as to_name
from chat c
left join usr u on c.chat_type is null and c.to = u.user_id
left join grp g on c.chat_type = 1 and c.to = g.group_id
where c.chat_type is null or c.chat_type = 1;
You have to use Union:
SELECT user.* from user join ... where chat.chat_type is null
Union
SELECT `Group`.* from `Group` join .... where chat.chat_type =1
if user and Group have a different number of column, you have to use a Default where you have less columns.
Hint: because Group is a Keyword, you should rename your table

SQL query left join issue

I am making a query but it is not working properly.
My table details are as follows:
Subarea:
id
Fieldsofstudy
student_subarea:
id primary key,
student_id ,
student_subarea Foreign key to subarea id and the student_subarea.
ASK:
What I want to accomplish is to obtain all fields of study in one column and in another column the id of the student if he is in the class. Otherwise, show null or something.
SELECT a.`id` , a.`name` , a.`area_id` , u. *
FROM `subarea` a
LEFT JOIN student_subarea u ON u.subarea_id = a.id
WHERE u.student_id =50
OR u.student_id IS NULL
Doing this is not helping at all. I tried to use functions and subqueries without any success. Could some help me.
The general rule for left join and filtering is to put the filtering clauses in the on clause for all but the first table. So this may do what you want:
SELECT a.`id`, a.`name`, a.`area_id`, u. *
FROM `subarea` a LEFT JOIN
student_subarea u
ON u.subarea_id = a.id AND u.student_id = 50;
How do you remember this logic? A left join returns all rows from the first table even when there is no match on the second table. That appears to be what you want.
The problem with your logic is that students other than student 50 match the logic. So, those rows get filtered out.
Move the filter criteria to the JOIN
SELECT a.`id` , a.`name` , a.`area_id` , u. *
FROM `subarea` a
LEFT JOIN student_subarea u
ON u.subarea_id = a.id
AND u.student_id =50
You should put the condition on the student ID inside the join condition, not in the where clause:
SELECT a.id, a.name , a.area_id, u.*
FROM subarea a
LEFT JOIN student_subarea u
ON u.subarea_id = a.id
AND u.student_id = 50

mysql leftjoin by max autoincrement id?

A) users
B) subscribtion
C) package information
I've table where B is a link between A and C , the query selected from A where B has row id for A and join C by B id .
Full example :
SELECT a.*,c.packageTitle
FROM users AS a
LEFT JOIN subscribe AS b ON (b.userid = a.userid)
LEFT JOIN package AS c ON (b.packageid = c.packageid)
my problem if user has multi subscription in C, i cannot get latest subscription row in loop query, i also used MAX(c.packageid) inside SELECT failed also .
Goal : get latest record in B assigned by A id .
any advice is very much appreciated
I don't think you were far off by trying to use MAX() to obtain the record with the latest package ID (which assumes that this ID is an increasing auto-increment column). In my answer below, the subquery identifies the latest package ID for each user record, using a GROUP BY. This subquery is then used to filter the correct records from your original query.
SELECT a.userid, b.*
FROM users AS a
LEFT JOIN subscribe AS b
ON b.userid = a.userid
LEFT JOIN package AS c
ON b.packageid = c.packageid
INNER JOIN
(
SELECT a.userid, MAX(c.packageTitle) AS maxPackageTitle
FROM users AS a
LEFT JOIN subscribe AS b
ON b.userid = a.userid
LEFT JOIN package AS c
ON b.packageid = c.packageid
GROUP BY a.userid
) t
ON a.userid = t.userid AND c.packageTitle = t.maxPackageTitle
As a note, this query would greatly benefit from something called a Common Table Expression (CTE), which is available in other RBDMS such as SQL Server and Oracle. A CTE would make the query much less repetitive and more readable.
This should be simple enough. In Mysql you just as you said put a max on the select along with a group by. So it would look something like:
SELECT username, id_info, ...
FROM
(
SELECT a.username, a.id_info, c.packageTitle, MAX(package_id)
FROM users AS a
LEFT JOIN subscribe AS b
ON b.userid = a.userid
LEFT JOIN package AS c
ON b.packageid = c.packageid
GROUP BY a.username, a.id_info, c.packageTitle
)
Remember to list all columns in the select which are also being grouped, except the one on which you are taking the max, or the query will fail.

MySQL Find and show all duplicates

I'm looking to find duplicates in a DB - but also show ALL the duplicate records. My current query:
SELECT 'duplicate' as dup,c.Id, c.CreatedDate, c.email, c.Lead_Grade__c, count(c.email)
FROM contact as c
Inner Join (select c.Id, c.email FROM contact as c group by c.email having count(c.email) > 1) as dup
ON c.email = dup.email
WHERE Lead_Grade__c is null;
This works to provide 1 row for each duplicate record. I want 2 (or more) rows for each duplicate record. So, if record X AND record Y both have the same email, then I'd like to show both.
Any thoughts?
Thanks!
This will join contact to itself and only show records where the email is the same that have more than 1 record (Assuming ID is a unique value)
This results set therefor should only be duplicates.
SELECT A.*
FROM contact A
INNER JOIN CONTACT B
on A.email = B.email
and a.id <> b.ID
ORDER BY A.Email

Find unique values that do not exist in multiple columns and tables

A misconfigured manual import imported our entire AD into our help desk user database, creating a bunch of extraneous/duplicate accounts. Of course, no backup to restore from.
To facilitate the cleanup, I want to run a query that will find users not currently linked to any current or archived tickets. I have three tables, USER, HD_TICKET, and HD_ARCHIVE_TICKET. I want to compare the ID field in USER to the OWNER_ID and SUBMITTER_ID fields in the other two tables, returning the only the values in USER.ID that do not exist in any of the other four columns.
How can this be accomplished?
Do a left join for each relationship where the right table id is null:
select user.*
from user
left join hd_ticket on user.id = hd_ticket.owner_id
left join hd_ticket as hd_ticket2 on user.id = hd_ticket2.submitter_id
left join hd_archive_ticket on user.id = hd_archive_ticket.owner_id
left join hd_archive_ticket as hd_archive_ticket2 on user.id = hd_archive_ticket2.submitter_id
where hd_ticket.owner_id is null
and hd_ticket2.submitter_id is null
and hd_archive_ticket.owner_id is null
and hd_archive_ticket2.submitter_id is null
How about something like:
SELECT id
FROM user
WHERE id NOT IN
(
SELECT owner_id
FROM hd_ticket
UNION ALL
SELECT submitter_id
FROM hd_ticket
UNION ALL
SELECT owner_id
FROM hd_archive_ticket
UNION ALL
SELECT submitter_id
FROM hd_archive_ticket
)
If I understood you situation I would do this:
SELECT a.id FROM user a, hd_ticket b, hd_archive_ticket c WHERE a.id != b.id AND a.id != c.id
You would want to try something like below. Inner query where I am doing Inner join with other 2 tables, will return only those user id which exist in all 3 tables. Then in your outer query I am just filtering out those ID's returned by inner query; since your goal is to get only those USER ID which is not present in other tables.
select ID
FROM USER
WHERE ID NOT IN
(
select u.ID
from user u
inner join HD_TICKET h on u.ID = h.OWNER_ID
inner join HD_ARCHIVE_TICKET ha on u.ID = ha.SUBMITTER_ID
)