I'm trying to keep track my students, and those that have not yet booked a lesson with me (I'm a music teacher as well as a CS student) but my attempt is actually giving me all those that HAVE already booked lessons, what is my mistake?
SELECT DISTINCT student.person_id FROM student, lesson
WHERE lesson.student = student.person_id
AND (select count(*)
FROM lesson
WHERE student = student.person_id
AND start_time > NOW()) = 0
Try:
SELECT DISTINCT s.person_id
FROM STUDENT s
WHERE NOT EXISTS(SELECT NULL
FROM LESSONS l
WHERE l.student = s.person_id
AND l.start_time > NOW())
Robert,
Making reasonable assumptions about how you might be storing information, your query selects those students for whom your database lists no future scheduled lesson. It doesn't matter whether a student has a past lesson or not. I'm not sure what you mean by "not yet booked a lesson," because that English phrase is somewhat awkward. Is it different from "not/never booked a lesson"? The words "not yet" indicate not before the present time, suggesting that you keep track of both booked lessons that have already been booked and also booked lessons that are "not yet booked" (whatever that means). Without a crystal ball, I don't know how you keep track of lessons that students have booked, but just not yet.
In any case, if for a particular student your database lists no lessons that start in the future for that student, you will see that student in your results (regardless of any lessons you list for that student that start now or in the past).
There's also an odd thing about your query, and that's the fact that you are joining the tables "lesson" and "student" on lesson.student = student.person_id before restricting the results based on a count. It seems to me that if you want a list of students satisfying some condition, you'd only need "student" in the FROM clause of the outer query, as in rexem's query.
If you want to see those students for whom you have no record of any lesson (regardless of lessons' start times), rexem's query should work. DISTINCT is unnecessary if the table "student" lists each student only once. The advantage of using EXISTS is that with EXISTS, as opposed to COUNT, you don't suggest needing to count up the total number of future lessons for each student before comparing the count with zero. With EXISTS, you suggest no need to keep looking for a student's future lessons once any such lesson is found.
Related
In class, professor said that SQL language does not provide 'for all' operator.
In order to use 'for all' you have to use 'not exist( X except Y)'
At this point, I can't figure out why 'for all' is same meaning as 'not exist( X except Y)'
I give you example relation:
course (cID,title,deptName,credit),
teaches (pID,cID,semester,year,classroom),
student (sID,name,gender,deptName)
Q: Find all student names who have taken all courses offered in 'CS' department
The answer is:
Select distinct
S.sid, S.name
from
student as S
where
not exists (
(select cID from course where deptName = 'CS')
except
(select T.cID from takes as T where S.sID = T.sID)
);
Can you give me specific explain about that?
ps. Sorry for my English skill
You professor is right. SQL has no direct way to query all records that have all possible relations of a certain type.
It's easy to query which relations of a certain type a record has. Just INNER JOIN the two tables and you are done.
But in an M:N relationship like "students" to "taken courses" it's not that simple.
To answer the question "which student has taken all possible courses" you must find out which relations could possibly exist and then make sure that all of them do actually exist.
select distinct
S.sid, S.name
from
student as S
where
not exists (
(select cID from course where deptName = 'CS')
except
(select T.cID from takes as T where S.sID = T.sID)
);
can be translated as
give me all students SELECT
for whom it is true: WHERE
that the following set is empty NOT EXISTS
(any course in 'CS') "all relations that can possibly exist"
minus EXCEPT
(all courses the student has taken) "the ones that do actually exist"
In other words: Of all possible relations there is no relation that does not exist.
There are other ways of expressing the same thought that can be used in database systems without support for EXCEPT.
For example
select
S.sid,
S.name
from
student as S
inner join takes as T on T.sID = S.sID
inner join course as C on C. cID = T. cID
where
c. deptName = 'CS'
group by
S.sid,
S.name
having
count(*) = (select count(*) from course where deptName = 'CS');
From your table definition and requirement its not clear what is the use of teaches table. You want the list of students names those have taken all courses offered by 'CS' department. For this students and course table is enough.
SELECT name
FROM
(
SELECT B.name, A.cid
FROM course A
INNER JOIN student B ON A.deptName = B.deptName
WHERE A.deptName = 'CS'
GROUP BY A.cid, B.name
) A
GROUP BY name
HAVING COUNT(name) >= (SELECT COUNT(cid) FROM course WHERE deptName = 'CS')
Internal query just selects all students those have taken any course offered by 'CS' dept and with group by I just make sure that in case a student take same course twice they will be counted as one row. Next I just select those students take all course offered by 'CS' dept.
I think you have some gap to understand your requirement properly. In your requirement no relation with teaches table is specified.
Q: Find all student names who have taken all courses offered in 'CS'
department
NOT EXISTS returns true if the query passed to it contains 0 records.
In this case, your sub-query from NOT EXISTS selects all the courses offered in 'CS', and subtract from this result set all the courses taken by specific student.
If the student have taken all the courses then except will remove all and the sub-query will return 0 records, which in pair with NOT EXISTS will give you true for specific student, and it will be displayed in final result set.
Brief history: Codd invented the Relational Model (RM), some people created a DBMS loosely based on RM to prove a RM product could be performant, and the SQL language emerged based on that DBMS (i.e. not directly based on the RM).
Codd came up with a set of primitive operators to define a database as being relationally complete. His algebra included product, where two relations are 'multiplied' together to give a combined relation; this made it into SQL as CROSS JOIN. [Side note: people refer to this operator as 'Cartesian product', which results in a set of ordered pairs. However, product in RM results in a relation (as do all relational operators), and CROSS JOIN results in a table expression (loosely speaking).]
Codd's algebra also included a division operator. I guess the thinking is, we should be able to take the result of product and one of the relations and use an operator to result in the other relation. But it does has some practical use too, of course. It is commonly expressed as 'the supplier who supplies all products', after Chris Date's parts and suppliers database found in his books. SQL lacks an explicit division operator, so we need to use other operators to get the desired result.
Note there are two flavours of division, being exact division ("suppliers who supply all the parts we are interested in and no more") and division with remainder ("suppliers who supply at least all the parts we are interested in and possibly more"). I tend to be wary of the answers here that do not mention either the name 'division' or that you need to decide whether you need to deal with remainders.
The thinking behind your professor's answer is that a double negative (in mathematics and English) i.e. if the statement "there is no part I don't supply" is true for a given supplier then that supplier will be in the result.
Note there are operators that Codd omitted (e.g. rename and summerize) that can now be found in SQL, so it's a shame we are still waiting for division!
When learing about joins, our instructor says to not skip tables.
For example, lets do a query that Selects the Last_Name, First_name, and Numeric_Grade.
I would write
Select Last_Name, First_Name, Numeric_Grade
From Student
Join Grade
Using(Student_id)
He says to write
Select Last_Name, First_Name, Numeric_Grade
From Student
Join Enrollment
Using(Student_id)
Join Grade
Using(Student_id)
Im confused because as long as long as i can link them through similar fields, i dont see the point of going enrollment.
He has not given me a reason for going through enrollment, other than its what the Diagram shows. Follow the diagram.
Do I have to go through Enrollment? Is it the safe way to do it, or does it not matter because Grade and Student have a Student_id primary key?
Quoting Alice Rischert in Oracle SQL By Example, lab 7.2:
The second choice is to join the STUDENT_ID from the GRADE table directly to the STUDENT_ID of the STUDENT table, thus skipping the ENROLLMENT table entirely. - - This shortcut is perfectly acceptable, even if it does not follow the primary key/foreign key relationship path. In this case, you can be sure not to build a Cartesian product because you can guarantee only one STUDENT_ID in the STUDENT table for every STUDENT_ID in the GRADE table. In addition, it also eliminates a join; thus, the query executes a little faster and requires fewer resources. The effect is probably fairly negligible with this small result set.
The only reason to go through the Enrollment table would be if you need information (fields) from that table. If both the Enrollment and Grade table have a Student_id field then you wouldn't need to go through Enrollment to get there.
In your example it looks like you are looking for First and Last Name, which should both come from the Student table and Numeric_Grade which should come from the Grade table. In this instance, there would be no need for the Enrollment table. If there were a WHERE clause that required something from the Enrollment table then yes you would need to include it, but your example I would say it is not needed.
If this is a question on a test or assignment and the teacher is requesting you go through the Enrollment table too I would do it just to appease him, but knowing that you don't actually need to do it to get the information that you require.
Depend on your tables. Sometimes you can but sometimes dont.
For example imagine in enrollment you have something like student_quit_course
Then you may only want grade of student actually finish the course and you need all three table
For this particular case you will have a GRADE for several section_id but to know what is that section you need [Section] and [Course] both join using [Enrollment]
I am creating an app that makes guest lists for greek life events at universities.
The two tables I am working with are 'student' table and 'participant' table.
The fields in the student table are: student_id, student_name, university, and chapter.
Students with chapter id's are considered members, and students without chapter id's are considered guests when making guest lists(participant table).
The participant table fields are: participant_id, member(which is related to student_id), guest (which is also related to student_id), and event.
When trying to add guests to the guest list for an event, I wrote the following sql query to filter out students from different universities and that aren't in chapters and weren't already on the list:
$student = getColumn("SELECT guest FROM participant WHERE event = '$event'");
$university = getSqlValue("SELECT university FROM student WHERE student_id = '$member'");
$f->setOption('filter',
"SELECT student_name
FROM `student`
LEFT JOIN participant ON student.student_id = participant.guest
WHERE student.chapter = ''
AND student.university = '$university'
AND participant.guest != '$student'");
So, I know this isn't going to work, because I have a whole array for $student, but even if I try it with one student id, the query doesn't work. It returns empty. If I remove the last AND particpant.guest!= $student, then the query returns all the students at the university that are not members of a chapter.
My question has two parts:
Why wouldn't that query work with one value for student?
Can someone think of a better way to go about doing this?
previously i thought that it's easy to store exams data in simple table like this :
id
subject_id
student_id
mark
date
but i noticed that it is very stupid idea cuz it makes database very huge
let's assume that we have school with 5000 students and there are 12 subjects for each students per month ... it means that our exams table will contain 5000*12*10 = 600000 row per year ,, ok what about if we decided to know student history from joining date to current date
.. i think it's very stupid and i think also there are optimum solutions to make another design to fit my needs ....
i need to store exams data in another lighter way
thank's in advance :)
Here is another way.
Table Student stores name, etc
Table Subject has subject names such as Reading, Writing and Arithmetic, and maybe a MinimumPassingMark.
Table Exam has ExamId, ExamDate, and SubjectID. It may also have PercentageOfOverallGrade
Table StudentExam has StudentID, ExamId, and mark.
Subjects and exams have a one to many relationship (one subject can have many exams, each exam has one subject. Students and exams have a many to many relationship.
So if you want to know if Johnny can read, it's as simple as.
select case
when sum(mark) * PercentageOfOverallGrade >= then 'pass' else 'no' end result
from Student s join StudentExam se on s.StudentId = se.StudentId
join Subject su on se.SubjectId = su.SubjectId
where s.name = 'Johnny'
and su.name = 'Reading'
I have a table of students and schools. How do I select the total students per school?
I'm sure this is a very simple query, however I'm not sure how to proceed on from this:
SELECT tblSchools.name
FROM tblStudentDetails
INNER JOIN tblSchools
ON tblStudentDetails.schoolId = tblSchools.id
Group by the school and use count() to count the students
SELECT s.name, count(d.id) as students_count
FROM tblSchools s
INNER JOIN tblStudentDetails d ON d.schoolId = s.id
GROUP BY s.name
I want to add on to the accepted answer as well. Working for a school district and continuously having to pull counts of students there are a few additional things to keep in mind. What students are you looking for?
Do you want active students, inactive students, or active and inactive students.
Do you want to include students that have been no showed (were going to come to your school, but ended up not coming for even a day, this is recorded in most student information systems.
Is the student attending multiple schools, in which case you want to exclude them from counting in their second or third school.
I've built the script with the idea of a normalized school district database, where things are broken out by school year, and enrollment.
Often a basic script for me looks a little like this.
SELECT s.SCHOOL_NAME, COUNT(stu.STUDENT_GU) AS STUDENT_COUNT
FROM STUDENT stu
JOIN STUDENT_YEAR sy ON sy.STUDENT_ID = stu.STUDENT_ID
JOIN SCHOOL_YEAR scy ON scy.SCHOOL_YEAR_ID = sy.SCHOOL_YEAR_ID
JOIN SCHOOL s ON s.SCHOOL_ID = scy.SCHOOL_ID
JOIN YEAR y ON y.YEAR_ID = sy.YEAR_ID
WHERE y.SCHOOL_YEAR = 2017
AND (sy.CONCURRENT IS NULL OR sy.CONCURRENT OR != 'Not Concurrent')
AND sy.ENTER_DATE IS NOT NULL
AND sy.STATUS IS NULL
GROUP BY s.SCHOOL_NAME
Because each school year is a new year, students, and schools usually have a table for the basic data that doesn't change. But also tables that are school year specific. In my example STUDENT_YEAR and SCHOOL_YEAR is where we get into the specifics regarding which kids we are actually getting, and where they currently are. I utilize the YEAR table to identify which school year I want to look at.
The STUDENT_YEAR table is where we store the students concurrency flag, enter date, and so within that table I can use in the WHERE clause a way to filter out Inactive Students, Concurrent Students, and ensure each student is counted only once.
If those year values aren't included, at least in my database, I would get all students ever enrolled for every year we've got stored.