Joins returning Null values? - mysql

Could anyone explain why I'm getting Null values for all but the first four records that my code returns?
My Teachers table has only 4 records so I imagine my join syntax is incorrect.
Sorry, I havn't fully gotten my head around joins yet.
USE Assignment
GO
CREATE VIEW PupilsAges AS
SELECT Pupil_ID,PupilDetails.FName,
PupilDetails.LName, PupilDetails.DOB,
DATEDIFF(year, GETDATE(),PupilDetails.DOB) AS "PupilAge",
Instrument,
(Teachers.FName+' '+Teachers.LName) AS Teacher
FROM Teachers JOIN PupilDetails
ON Teachers.ID = PupilDetails.Pupil_ID

Your joining Teachers.ID = PupilDetails.Pupil_ID
This looks to be the problem, you have not listed the schema for the tables, however try something similar to this:
USE Assignment
GO
CREATE VIEW PupilsAges AS
SELECT Pupil_ID,PupilDetails.FName,
PupilDetails.LName, PupilDetails.DOB,
DATEDIFF(year, GETDATE(),PupilDetails.DOB) AS "PupilAge",
Instrument,
(Teachers.FName+' '+Teachers.LName) AS Teacher
FROM Teachers JOIN PupilDetails
ON Teachers.ID = PupilDetails.Teacher_ID

You want to join to a field that relates data between the two tables. In tea hers the id field should identify a teacher. In pupilDetails pupil_id identifies a pupil. You want to join on a teacher_id field, if one exists.
With your current query you only have 4 teachers so once you pass the first 4 students it doesn't know who to join students 5+ to. When you join on the proper field the teachers should repeat.

Related

count students from table where join mysql

I have the databaase in icon below. I want
to count all students from Subject with name Psychology and class with name Class5.
the percentage of students with status "Something" from subject with name Psychology and class with name Class5.
All students and the class name from Class "Class6" that are male.
I've tried for example
(in english:)
SELECT COUNT(student_name) AS NumberOfStudents FROM student_srms JOIN class_srms JOIN subject_srms WHERE class_srms.class_name='Class5' AND subject_srms.subject_name='Psychology'
But returns NumberOfStudents = 20, but 20 are all student entries.
The issue likely stems from your FROM clause. It's not enough to just say JOIN. You need to specify the relationship of the columns between the two tables being joined with an ON clause:
FROM student_srms
JOIN class_srms
ON student_srms.student_id = class_srms.student_id
JOIN subject_srms
ON class_srms.subject_id = subject_srms.subject_id
I believe in MySQL there is a NATURAL JOIN which will tell mysql without an ON clause to just join on column names that are similar between the two tables, but that feels dirty to me and could cause failures later on in an applications lifecycle if new columns are introduced to tables that share names, but not relationships, so I would just steer clear of that.
I have a suspicion that your diagram showing tables/columns is incorrect based on the error you are reporting in the comments. Instead, try (and I'm totally guessing blind here at this point):
FROM student_srms
JOIN student_class
On student_srms.student_id = student_class.class_id
JOIN class_srms
ON student_class.class_id = class_srms.student_id
JOIN subject_srms
ON class_srms.subject_id = subject_srms.subject_id
That adds in that student_class relationship table so you can make the jump from student to class tables. Fingers crossed.

Primary key from left join

My doubt raises after i did this:
select name
from Highschooler
where ID in(select Friend.ID2
from Highschooler left join Friend
on Friend.ID1 = '1911' or Friend.ID1 = '1689');
The tables can be found here
The expected result was correct, and respects this clause:
Find the names of all students who are friends with someone named Gabriel.
Notice that i did not make any reference to the table Highschooler.ID
This seemed intuitive to me but then it got me thinking as Highschooler table does not have ID selected as primary key in my workbench.
So, when doing a left join, how does mysql know that i want to pair ID from highschooler with a column from Friend? The tables don't have any column name in common. So for all i know sql could try to pair grade from Highschooler, with ID1 from Friend.
The answer is that MySQL does not know how to join tables. You have to tell MySQL how to join the tables. In case of an outer join, use the on clause. However, in this particular case you do not need an outer join, since you want ids from the friend table.

Select from a table the ones that don't have a relationship with another table

The specific problem is listing the names of the teachers that never graded.
I have 'teachers' table with the columns 'Name' and 'ID'.
And 'grades' table with the column 'IDTeacher' and 'Grade'.
Don't get why this doesn't work:
Select Name from teachers where not exists(Select * from grades, teachers)
You can just join it with the grades table and use the ones where the join returns "null" for the right side:
SELECT
name
from
teachers t
LEFT JOIN
grades g
on
t.teacher = g.teacher
WHERE
ISNULL(g.teacher)
edit: Thought about a right join instead, but no, the right join might not work, if the teacher has no entry in the grades table. (Then you would miss him completely, even if he is in the teacher table)
You could also use WHERE IN for this:
SELECT
name
FROM
teachers
WHERE
name
NOT IN (SELECT name from grades)
BUT the MySQL Optimizer will rewrite this to exactly the correlated subquery #Gordon Linoff has written. Using WHERE NOT IN is just easier to read imho.
Your query does work, it just doesn't do what you think it should. The subquery creates a cartesian product between the two tables. If both tables have rows, then the cartesian product has rows and the where clause will always be true.
You can take this approach, but you need a correlated subquery:
Select Name
from teachers t
where not exists (Select 1 from grades g where g.idteacherid = t.id);
Note that this query only has one table in the subquery.
There are other ways to write this query, but this seems to be the approach you are heading in. And, not exists is a very reasonable approach.

Mysql query for selecting friends

I am trying to solve this "issue", however still without success. What I'd like to achieve is, create a query that will select all friends of specific actor. Let's say I want to get list of First name, Last name and age of Jason Statham's friends.
Below is an image of tables.
PS: Are those tables correctly organized ? (especially those foreign keys)
Thanks in advance
Does this do what you're looking for?
SELECT actors.first_name,
actors.last_name
FROM actors
WHERE actors.login IN
(
SELECT friendslist.loginf
FROM friendslist
WHERE friendslist.logina = 'xstad'
)
You'll need to include the Actors table twice - once for the focus person (Jason Statham) and once for his friends.
SELECT CONCAT(A.first_name," ",A.last_name) AS Actor, CONCAT(B.first_name," ",B.last_name) AS Friend
FROM Actors AS A
JOIN [Friends List] AS F on A.login=F.loginA
JOIN Actors AS B on F.loginB=B.login
ORDER BY A.last_name, B.last_name
If Friends_List is rows where "[loginA] and [loginF] are friends" then rows should appear in pairs, < a1,a2> and < a2,a1>. I'll assume it means "[loginA] considers [loginF] a friend" and that in your query "all friends of an actor" means "all actors that an actor considers a friend".
You can do this with natural join. It joins on common columns and returns only one column with that name. If you want two differently named columns joined to each other then you have to rename one. Unfortunately in SQL you can't do that by just mentioning the one column, you must mention them all.
// first_name, last_name of rows satisfying [login] has name [first_name] [last_name] AND 'xstad' considers [login] a friend
SELECT first_name,last_name
FROM Actors
NATURAL JOIN
(SELECT loginA, loginF AS login
FROM
(SELECT * FROM Friends_List WHERE loginA='xstad')
)
(You could collapse the nested selects but I am illustrating the structure.)
You could also use NATURAL JOIN without renaming but explicity equating columns:
// <firstname,last_name> of rows satisfying [login] has name [first_name] [last_name] AND [login] considers [login] a friend AND loginA='xstad' AND login=loginF
SELECT first_name,last_name
FROM Actors
NATURAL JOIN Friends_List
WHERE loginA='xstad' AND login=loginF
EDIT
A certain design & programming style not familiar to or understood by most SQL programmers is supported by natural join. This approach lets relational algebra operators parallel logic operators: result rows satisfy the statement that is the AND of the statements that argument rows satisfy; UNION the OR; EXCEPT the AND NOT; PROJECT on all but some columns {C,...} the EXISTS C,..; etc.) This is simpler than having to deal with the dotted duplicate columns from SQL INNER JOIN. Unfortunately SQL does not give all the relevant support (eg rename columns, project out columns, no SQL pseudo-3VL, optimizations).
EDIT corrected 1st query

Join of tables returning incorrect results

There are 4 sql tables:
Listings(Amount, GroupKey, Key, MemberKey),
Loans(Amount, GroupKey, Key, ListingKey),
Members(City, GroupKey, Key)
Groups(GroupRank, Key, MemberKey)
Now, if one wants to find out the loans which are also listings and find the members city and GroupRank for the members in the loan table. Here, the group table contains information about grous of which members are a part of.
and also perform a select operation as given below:
select Listings.Amount, Members.City, Groups.GroupRank
from listings, loans, members, groups
where Listings.Key=Loans.ListingKey and
Members.Key=Listings.MemberKey and
Listings.GroupKey=Groups.Key
The above join is giving an incorrect result, please point out where I am going wrong.
Also I am new to SQL so please excuse the novice question.
Note: The following is just a guess what your problem is. Like others said, clearify your question.
You want to JOIN
( http://dev.mysql.com/doc/refman/5.1/de/join.html )
those tables. What you write is just another form of a join, meaning it has the same effect. But you "joined" a bit too much. To make things clearer a syntax has been invented to make things clearer and avoid such mistakes. Read more about it in the link given above.
What you want to achieve can be done like this:
SELECT
Listings.Amount, Members.City, Groups.GroupRank
FROM
Listings
INNER JOIN Groups ON Listings.GroupKey=Groups.Key
INNER JOIN Members ON Members.Key=Listings.MemberKey
You don't do a SELECT on the Loans table, you don't need it in this query.
This is the INNER JOIN which will give you a result where every row in table A has an according entry in table B. When this is not the case, you have to use the LEFT or RIGHT JOIN.
Maybe the problem is related to the join type (INNER). Try LEFT JOIN for example but Mark has right: you should clearify your question.
I would firstly change your query to use the more modern join syntax, which allows outer joins. Tr this:
select Listings.Amount, Members.City, Groups.GroupRank
from listings
left join loans on Listings.Key=Loans.ListingKey
left join members on Members.Key=Listings.MemberKey
left join groups on Listings.GroupKey=Groups.Key
and/or Loans.GroupKey=Groups.Key
and/or Members.Key=Groups.MemberKey
You may need to play with the criteria on the last join (maybe they should be "or" not "and" etc).