SQL query left join issue - mysql

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

Related

how to use full outer join by removing inner join

I am new to MySQL I have one query which works perfectly fine with inner join but with inner join some records got missing I want all the data from both the table but when i use full outer join or full join it gives error unknown column classroom.id in field list
here is the query
SELECT
classroom.id as id,
classroom.grade as grade,
classroom.status as status,
teacher.id as tid,
teacher.name as tname
FROM classroom
FULL JOIN teacher on classroom.teacherId = teacher.id
ORDER BY grade ASC
these are my two tables you can see in the picture enter image description here
and also I mention in column
classroom
id,grade,teacherid,status
teacher
id,email,password,name,status,role
MySQL does not support a FULL OUTER JOIN or FULL JOIN, you have to emulate it using UNION with LEFT JOIN and RIGHT JOIN.
Read more about it here: Why does MySQL report a syntax error on FULL OUTER JOIN?
So your syntax should look like this:
SELECT * FROM
(SELECT
a.id as id,
a.grade as grade,
a.status as status,
b.id as tid,
b.name as tname
FROM classroom a
LEFT JOIN teacher b ON a.teacherId = b.id
UNION
SELECT
a.id as id,
a.grade as grade,
a.status as status,
b.id as tid,
b.name as tname
FROM classroom a
RIGHT JOIN teacher b ON a.teacherId = b.id) c
WHERE c.grade != '' AND c.grade IS NOT NULL
ORDER BY c.grade ASC
UPDATE: Per your comments below, I've include a WHERE clause to remove NULL values AND empty '' values. You could also write a WHERE clause in each of the UNION queries above but I find it easier to put it in a subquery and write the WHERE clause once in the outer query. I've also added aliases a, b, c so its easier to read vs. using the table names.
Demo here.

SUM mixed with LEFT JOIN and GROUP BY in MYSQL query

I am having some trouble with a query that involves sum, a left join and a group by
$sql = "
SELECT h.id AS hid
, SUM(l.likes) AS likes
FROM homes h
LEFT
JOIN likes l
ON l.homeid = h.id
GROUP
BY h.id
";
Instead of summing the likes for each home, it is giving NULL if the home has no likes or the number 8873 if it has one like. I really can't understand the 8873.
Of note, there are a lot of likes in this table for other things in which case the value for l.homeid is NULL. Could that be throwing things off?
Edit:
I added another like for a homeid from a different user and now it is giving me 8906 instead of 8873 for those with 1 like and 17812 for the one with two likes. This is very strange. The data type for all the numbers is int(11). I am going to create a totally new table and see if that one does the same thing. I'm also going to remove a unique index I added recently.
Try moving the aggregation into a derived table and joining then joining that:
SELECT
h.id AS hid
, COALESCE( l.likes, 0 ) AS likes
FROM homes h
LEFT JOIN (
SELECT
homeid
, COUNT( likes ) AS likes
FROM likes
GROUP BY
homeid
) AS l ON h.id = l.homeid
Also try COUNT() instead of SUM()

sql join returns fields with null value

I have the following query:
SELECT *
FROM tableA.A
LEFT JOIN tableB AS B ON B.id=A.id
LEFT JOIN tableC AS C ON C.id=A.id2
LEFT JOIN tableD AS D ON D.id=A.id3
WHERE D.id = '124' AND A.field = 1
GROUP BY A.id ORDER BY D.sortorder
The structure above is identic with my real query and i want to mention that all tables i used in the query are valid and rows are populated with numeric and alphabetic characters.There is no NULL value anywhere.
The problem is that, after i execute this query, it returns some fields with NULL values even though they are not null.
I tried to explain as good as i could,but it's a strange behaviour and i couldn't find anything on google.
If it's not a common issue and it's hard to find the mistake, maybe some suggestions would help me find the bug.
Thank you in advance
UPDATE I want to apologize.The problem was caused by an enter at the end on table A, that's why it returned NULL because there was actually no match.Thank you for your help
Try this query:
SELECT *
FROM tableA.A
LEFT JOIN tableB AS B ON B.id=A.id
LEFT JOIN tableC AS C ON C.id=A.id2
LEFT JOIN tableD AS D ON D.id=A.id3 and D.id = '124'
WHERE A.field = 1
GROUP BY A.id
ORDER BY COALESCE(D.sortorder,0)
Conditions on the right table of a LEFT JOIN should be placed inside the ON clause , not the WHERE clause.
If that doesn't work either, then I thing you misunderstood the LEFT JOIN purpose . It is used to keep all the records from the master table(A in your case) and discard all the data that doesn't match from the detail table, so , there will be NULL value when no match fouhd .

How to select COUNT of one table column where there are no matches in another table column

I have two MySQL tables that are relational based on an ID number. I need to select the count of the IDs in the first table that do NOT match any ID in the second table. This is what I tried:
SELECT COUNT(DISTINCT(ask_questions.id))
FROM ask_questions
INNER JOIN ask_answers ON ask_questions.id != ask_answers.question_id;
I thought that using the "!=" would return results that do not match but the number returned is not correct. Is there a better solution?
use LEFT JOIN since you want to get ID that do not have atleast a match on the other table.
SELECT COUNT(DISTINCT(ask_questions.id))
FROM ask_questions
LEFT JOIN ask_answers
ON ask_questions.id = ask_answers.question_id
WHERE ask_answers.question_id IS NULL
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
An alternative with JOIN is by using NOT EXISTS
SELECT COUNT(DISTINCT(id))
FROM ask_questions
WHERE NOT EXISTS
(
SELECT null
FROM ask_answers
WHERE ask_questions.id = ask_answers.question_id
)
Use NOT IN
SELECT COUNT(ask_questions.id)
FROM ask_questions
WHERE ask_questions.id NOT IN(SELECT question_id FROM ask_answers)
SELECT COUNT(DISTINCT(ask_questions.id))
FROM ask_questions
LEFT JOIN ask_answers ON ask_questions.id = ask_answers.question_id;
WHERE ask_answers.question_id IS NULL
The left join will let you get the ask_questions even when they don't have ask_answers.
The ones that don't have ask_answers will have the id null
Use except:
select count(*) from
(select id from questions
except
select id from ask_answers_questions) as subtable;
EXCEPT will remove duplicates for you.
--dmg
You want to outer join the tables, not inner join them, and select the columns in the second table that are null.
SELECT COUNT(DISTINCT(ask_questions.id))
FROM ask_questions
LEFT JOIN ask_answers ON ask_questions.id = ask_answers.question_id
WHERE ISNULL(ask_answers.id)

MySQL LEFT JOIN Multiple Conditions

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."%';