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.
Related
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.
I'm creating a database for comics. Right now I have 3 main tables (comics, publishers, people) and 3 junction tables (person2comic, publisher2comic and person2publisher). I want to be able to have a search form that allows searching by any combination of title, issue number, publisher, and person. When referencing only one junction table, I use a variation of this depending on what's being searched for:
SELECT comicTitle, comicIssue, firstName, lastName
FROM person2comic
JOIN comics ON comics.comicID = person2comic.comicID
AND comics.comictitle LIKE "%walk%" ;
If someone were to search by title, publisher and person, I'm not sure how to set up the statement since it would require using two of the junction tables. Would it be a nested query situation or something else?
You can have arbitrarily many joins. Not exactly sure on all of your column names, but this should roughly work:
SELECT *
FROM people
JOIN person2comic p2c ON people.id = ptc.person
JOIN comic ON p2c.comic = comic.id
JOIN publisher2comic pub2c ON comic.id = pub2c.comic
JOIN publisher ON pub2c.publisher = publisher.id
Also note that your schema may be inefficient if you relationships all aren't many-to-many. See my comment.
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
In a MySQL database I have two tables linked in a join. One table contains people details and another book details. I want to search the databases for a particular author (principalWriter) and return all the co-authers (additionalWriters) they have worked with.
So I use
SELECT
books.additionalWriters,
people.name
FROM
books
INNER JOIN people ON books.principalWriter = people.personID
WHERE personID = 1;
And this returns each book the author has worked on with the additional writers ID.
However how can I then use these returned IDs to look up their respective names in the name table? Is there a single query I can do to accomplish this?
The problem here is not the query itself but rather the database design. You should have this tables:
Writers(*ID*, name): Will store all writers (principal or not)
Books(*ID*, name): Will store all books
Writers_Books(*WriterID*, *BookID*, Principal): This will store the relationship between the writers and the books and will specify if the writer for that book is principal or not
Primary keys are surrounded by asterisks
Note: You could also remove the Principal field and add it to the Books table, but if a book happens to have to principal writers, you won't be able to solve that with that schema.
Once you update your design, the query will be much easier.
you need to join it again to peoples table. try this:
SELECT a.AdditionalWriters, c.name, b.name
FROM books a INNER JOIN people b ON
a.PrincipalWriter = b.personID
INNER JOIN people c ON a.additionalWriters = c.PersonID
WHERE b.PersonID = 1
Try the following:
SELECT people.name FROM people WHERE personID in
(SELECT
books.additionalWriters,
FROM
books
INNER JOIN people ON books.principalWriter = people.personID
WHERE personID = 1);
MySQL setup: step by step.
programs -> linked to --> speakers (by program_id)
At this point, it's easy for me to query all the data:
SELECT *
FROM programs
JOIN speakers on programs.program_id = speakers.program_id
Nice and easy.
The trick for me is this. My speakers table is also linked to a third table, "books." So in the "speakers" table, I have "book_id" and in the "books" table, the book_id is linked to a name.
I've tried this (including a WHERE you'll notice):
SELECT *
FROM programs
JOIN speakers on programs.program_id = speakers.program_id
JOIN books on speakers.book_id = books.book_id
WHERE programs.category_id = 1
LIMIT 5
No results.
My questions:
What am I doing wrong?
What's the most efficient way to make this query?
Basically, I want to get back all the programs data and the books data, but instead of the book_id, I need it to come back as the book name (from the 3rd table).
Thanks in advance for your help.
UPDATE:
(rather than opening a brand new question)
The left join worked for me. However, I have a new problem. Multiple books can be assigned to a single speaker.
Using the left join, returns two rows!! What do I need to add to return only a single row, but separate the two books.
is there any chance that the books table doesn't have any matching columns for speakers.book_id?
Try using a left join which will still return the program/speaker combinations, even if there are no matches in books.
SELECT *
FROM programs
JOIN speakers on programs.program_id = speakers.program_id
LEFT JOIN books on speakers.book_id = books.book_id
WHERE programs.category_id = 1
LIMIT 5
Btw, could you post the table schemas for all tables involved, and exactly what output (or reasonable representation) you'd expect to get?
Edit: Response to op author comment
you can use group by and group_concat to put all the books on one row.
e.g.
SELECT speakers.speaker_id,
speakers.speaker_name,
programs.program_id,
programs.program_name,
group_concat(books.book_name)
FROM programs
JOIN speakers on programs.program_id = speakers.program_id
LEFT JOIN books on speakers.book_id = books.book_id
WHERE programs.category_id = 1
GROUP BY speakers.id
LIMIT 5
Note: since I don't know the exact column names, these may be off
That's typically efficient. There is some kind of assumption you are making that isn't true. Do your speakers have books assigned? If they don't that last JOIN should be a LEFT JOIN.
This kind of query is typically pretty efficient, since you almost certainly have primary keys as indexes. The main issue would be whether your indexes are covering (which is more likely to occur if you don't use SELECT *, but instead select only the columns you need).