Native Query to Select records to only contain specific ids - sql

I am in the process of implementing an advanced search in my application. I'm sort of new with Oracle and JPA. The database structure has a many-to-many relationship (ERD) with an intermediate table that contains StudentID and CourseID.
I'm trying to return rows of students that have the list of classes/courses.
Basically, I want the results of
SELECT DISTINCT s.* FROM STUDENT s
INNER JOIN STUDENT_COURSE sc ON s.StudentID = sc.StudentID
INNER JOIN COURSE c ON c.CourseID = sc.CourseID
WHERE ( c.CourseID IN (SELECT DISTINCT CourseID FROM STUDENT_COURSE WHERE CourseID = 'A01') AND c.CourseID IN (SELECT DISTINCT CourseID FROM STUDENT_COURSE WHERE CourseID = 'A02'));
which returns the records of students that have both courses 'A01' and 'A02'.
ID
Age
Grade
1
...
...
4
...
....
9
...
....
with courses
Courses
A01,A02
A01,A02,A03,X02
A01, A02, A03
The goal is to get a similar result using Spring Data JPA. And make it more general to select any number of Course Ids.
I've tried
#Query(value="SELECT DISTINCT s.* FROM STUDENT s "
+"INNER JOIN STUDENT_COURSE sc ON s.StudentID = sc.StudentID "
+"INNER JOIN COURSE c ON c.CourseID = sc.CourseID "
+"WHERE ( s.STUDENTID IN (SELECT DISTINCT STUDENTID FROM STUDENT_COURSE WHERE CourseID =:courseIds)",nativeQuery=true))
public List<Student> advancedSearch(#Param("courseIds") String courseIds);
One example, The courseIds field contain "A01,A02". The result would be empty.
I've looked at examples where people use IN. When I tried it, it would return records of the student have courses AO1 OR A02 OR Both.
DON'T WANT THIS
ID
Age
Grade
2
...
...
3
...
....
8
...
....
With Courses
CourseID
A01,A03
A01, X01
A02
I want records of students that have both A01 AND A02 as shown in the other table.

My guess is that the query you want is
select s.name /* note this column doesn't appear in your ERD */
,s.age
,s.grade
from student s
join student_course sc
on s.studentID = sc.studentID
where sc.courseID IN ('A01', 'A02')
group by s.name /* again, this column isn't in your ERD */
,s.age
,s.grade
having count(sc.courseID) = 2
That doesn't produce the output table you say you want. But neither does the query you posted. This will return all the students that have taken both courses (you could add a distinct to the having clause if the data model were to change to allow a student to take a course multiple times). It won't give you the list of all courses that student has taken as a comma-separated list. But the query you posted doesn't return any course information either.
If this isn't what you are looking for, it would be really helpful to update your question with
The DDL for your schema in text form (so we can run it) rather than as an image
The DML to insert whatever sample data you want
The actual results you'd want the query to return (since there is a conflict between what the query you posted returns, the table of data you say you want, and the descriptive text of what you are trying to accomplish, it is confusing to try to figure out which is right).

Related

How to make sure result pairs are unique - without using distinct?

I have three tables I want to iterate over. The tables are pretty big so I will show a small snippet of the tables. First table is Students:
id
name
address
1
John Smith
New York
2
Rebeka Jens
Miami
3
Amira Sarty
Boston
Second one is TakingCourse. This is the course the students are taking, so student_id is the id of the one in Students.
id
student_id
course_id
20
1
26
19
2
27
18
3
28
Last table is Courses. The id is the same as the course_id in the previous table. These are the courses the students are following and looks like this:
id
type
26
History
27
Maths
28
Science
I want to return a table with the location (address) and the type of courses that are taken there. So the results table should look like this:
address
type
The pairs should be unique, and that is what's going wrong. I tried this:
select S.address, C.type
from Students S, Courses C, TakingCourse TC
where TC.course_id = C.id
and S.id = TC.student_id
And this does work, but the pairs are not all unique. I tried select distinct and it's still the same.
Multiple students can (and will) reside at the same address. So don't expect unique results from this query.
Only an overview is needed, so that's why I don''t want duplicates
So fold duplicates. Simple way with DISTINCT:
SELECT DISTINCT s.address, c.type
FROM students s
JOIN takingcourse t ON s.id = t.student_id
JOIN courses c ON t.course_id = c.id;
Or to avoid DISTINCT (why would you for this task?) and, optionally, get counts, too:
SELECT c.type, s.address, count(*) AS ct
FROM students s
JOIN takingcourse t ON s.id = t.student_id
JOIN courses c ON t.course_id = c.id
GROUP BY c.type, s.address
ORDER BY c.type, s.address;
A missing UNIQUE constraint on takingcourse(student_id, course_id) could be an additional source of duplicates. See:
How to implement a many-to-many relationship in PostgreSQL?

PostgreSQL: How do I get data from table `A` filtered by a column in table `B`

I want to fetch all parents that have kids in a specific grade only in a school.
Below are trimmed down version of the tables.
TABLE students
id,
last_name,
grade_id,
school_id
TABLE parents_students
parent_id,
student_id
TABLE parents
id,
last_name,
school_id
I tried the below query but it doesn't really work as expected. It rather fetches all parents in a school disregarding the grade. Any help is appreciated. Thank you.
SELECT DISTINCT
p.id,
p.last_name,
p.school_id,
st.school_id,
st.grade_id,
FROM parents p
INNER JOIN students st ON st.school_id = p.school_id
WHERE st.grade_id = 118
AND st.school_id = 6
GROUP BY p.id,st.grade_id,st.school_id;
I would think:
select p.*
from parents p
where exists (select 1
from parents_students ps join
students s
on ps.student_id = s.id
where ps.parent_id = p.id and
s.grade_id = 118 and
s.school_id = 6
);
Your question says that you want information about the parents. If so, I don't see why you are including redundant information about the school and grade (it is redundant because the where clause specifies exactly what those values are).

SQL query with more than 2 tables

I'm doing an exercise on ORACLE SQL.
Currently I got 3 tables.
Student values = "student_id ,name"
Subjects values = "subject_id, name"
Scores values = "score, student_id, subject_id"
I'm trying to retrieve the following information from my database.
Name of student, Name and id of the subject and finally the score that has the student_id "34560".
SELECT scores.score,
scores.subject_id,
student.name,
subject.subject_id,
subject.name
FROM scores
INNER JOIN students
ON scores.student_id = '34560'
INNER JOIN subject
ON /* and here's where i'm lost*/
Is there a way to put all together from the first part of the query where I call the list of students with student_id = "34560" and then query that list to see if it matches with the subject_id?
Use in operator for list of student id
SELECT sc.score, sc.subject_id,
st.name, sb.subject_id, sb.name
FROM scores sc
INNER JOIN students st
ON sc.student_id = st.student_id
INNER JOIN subject sb
ON sc.subject_id=sb.subject_id
where sc.student_id in ('34560','add_anotherstudentid','add_anotherstudentid') //you can add multiple student id

Difficulty understanding a SQL Join query

I have these tables in my database:
Student:
id,
style_id,
instrument,
name,
Teacher:
id,
style_id,
name
lessons:
id,
style_id,
teacher_id,
student_id,
month
And I'm trying to write a query that returns every student enrolled for a particular month and their teacher and style e.g. it would return something like this:
March
Student Name Teacher Style
-------------------------------
Glen Bob Jazz
Missy Bruce Rock
So far all I got is something like this (I know I need to use joins just don't know how):
SELECT
students.name, teacher.name, style.style_name
FROM
lessons
WHERE
month = "March"
JOINS students, teachers
First off, it is not a good practice for you to have the name of the table in your primary key, in your table teacher, you used musician_id, use teacher_id instead. This is the code I would use to achieve what you are trying to do.
SELECT a.style_name, b.name, c.name, d.month
FROM lessons d
INNER JOIN Styles a ON a.style_id = d.style_id
INNER JOIN Student b ON b.student_id = d.student_id
INNER JOIN Teacher c ON c.teacher_id = d.teacher_id
WHERE d.month = "march";
Since you are in difficulty with joins, Inner join, will see if its evidence of the ids in both tables to return true, thats why it solvs your problem.
To answer your specific question,
SELECT Student.name AS Student, Teacher.name AS Teacher, Styles.style_name AS Style
FROM lessons
INNER JOIN Styles ON lessons.style_id = Styles.style_id
INNER JOIN Teacher ON lessons.teacher_id = Teacher.musician_id
INNER JOIN Student ON lessons.student_id = Student.student_id
WHERE lessons.month="March";
You might want to look at your table design, though. You have a style_id in the lessons, the Teachers and the Students tables. The query above matches the style name with the style_id in the lessons table, while it could be linked to either the Teacher table or the Student table. This could lead to reporting problems if Bob is teaching a Jazz lesson and his profile says he's a Rock teacher.
It's better to remove the style_id from the Teacher and Student tables and introduce a new table
Interests: participant_id (could be teacher id or student id), role ('teacher' or 'student'), style_id

SQL Join Issue with Nulls

I have 7 tables I am using in a view. For examples, I will be using these as my table names (The Fields within the table don't matter for this execpt that the PrimaryKey is tableName + ID)
Table 1.
Teacher
Table 2.
Student (Exception-- Student has all the ids in it, from all the other 6 tables)
Table 3.
Science
Table 4.
Math
Table 5.
History
Table 6.
German
Table 7.
Language Arts
Now, All the tables from 3-7 have a relationship to Student from Table 2. And Student has a relationship to teacher.
My view currently works if any of my tables have any fields. and some can be null, it also works if any of my tables 3-7 are completely null, it will still display.
However, my current problem is, if my teacher has no students assigned to them, making tables 2-7 null, empty, etc.... My query doesnt even return the teacher info that is filled in... First name, last name, Date of birth, etc.
How can I Accomplish this?
I tried doing all left joins from all the tables, since the teacher can have null fields, I tried doing an inner join from dbo.Teacher as Teacher Inner Join dbo.Student on dbo.Student.TeacherID = Teacher.TeacherID but that didnt work.. I am at a loss...
SELECT Teacher.TeacherID ,
Student.StudentID ,
Science.ScienceID ,
History.HistoryID ,
Math.MathID ,
German.GermanID ,
LanguageArts.LanguageArtsID
FROM dbo.Teacher AS Teacher
LEFT OUTER JOIN dbo.Student
ON dbo.Student.TeacherID = Teacher.TeacherID
LEFT OUTER JOIN dbo.Science AS Science
ON dbo.Student.ScienceID = Science.ScieneID
LEFT OUTER JOIN dbo.Math AS Math
ON dbo.Student.MathID = Math.MathID
LEFT OUTER JOIN dbo.History AS History
ON dboStudent.HistoryID = History.HistoryID
LEFT OUTER JOIN dbo.German AS German
ON dbo.Student.GermanID = German.GermanID
LEFT OUTER JOIN dbo.LanuageArts AS LanguageArts
ON dbo.Student.LanguageArtsID = LanguageArts.LanguageArtsID
Two comments:
Do you know the use of LEFT JOIN?. This query should return all teachers, even thouse with no students.
SELECT *
FROM teacher t LEFT JOIN student s ON s.teacher_id = t.id
(RIGHT JOIN would work if you want all student even if they do not have teachers)
Remmember that in SQL 1 == NULL and 1 != NULL are both false. So the following query will not result a teacher without students or a student without teachers.
SELECT *
FROM teacher t,
student s
WHERE s.teacher_id = t.id
I figured out my answer, in my select i was using dbo.Student.TeacherID, instead of dbo.Teacher.TeacherID, therefore my query was always coming back with null TeacherID values since I was checking my view with a query like this one
Select * from MyView Where TeacherID = 1;
This returned null since my select was pulling Student.TeacherID which is null, so I Swapped out dbo.Student.TeacherID for dbo.Teacher.TeacherID and it is now resolved.
Such a bleh moment. Thanks for comments and replies.!
As I am reading back in my OP, I said I was selecting
SELECT Teacher.TeacherID ,
Student.StudentID ,
which was technically a typo, but also my answer...