sorry for the question, I'm usually using PostgreSQL but MySQL I can't find my legs In it,
I have this DB :
create table Students (
Student_id int,
Student_name varchar(100)
);
create table Grades
(
student_id numeric,
Profession varchar(10),
Grade numeric
);
insert into Students(Student_id,Student_name) values (1,"avi"),(2,"david"), (3,"mosh"), (4,"adir");
insert into Grades values (2,'math',95), (3,"sport",25), (4,"english",30);
insert into Grades(student_id,Profession) values (1,'math');
I want to get the student name the other profession paper more than once
in this example the output will be:
avi
david
because there both learning math
this is my attempt so far:
select
student_name,
profession
from Students
inner join Grades
on Students.Student_id = Grades.Student_id
group by profession
count(profession) > 1;
this is a link to SQL fiddle
Subquery returns profession wise student count and join with student and grades for retrieving final result where no_of_student per profession appears more than one.
-- Mysql
SELECT s.student_name
FROM Students s
inner join Grades g
on s.Student_id = g.Student_id
inner join (SELECT Profession
, COUNT(1) no_of_std
FROM Grades
GROUP BY Profession) t
on g.Profession = t.Profession
AND t.no_of_std > 1
order by s.student_id
Please check this url https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=a59293c694549e39bcf1678050f6b6f1
N.B.: This query is also applicable for all RDBMS (PostgreSQL, MSSQL, MySQL, ORACLE) because all basics syntax are used here.
Latest version of mysql(v5.8) where analytical function supports and this will also work postgresql, MSSQL etc
SELECT t.student_name
FROM (SELECT s.Student_id, s.student_name
, COUNT(s.Student_id) OVER (PARTITION BY Profession) no_of_std
FROM Students s
inner join Grades g
on s.Student_id = g.Student_id) t
where t.no_of_std > 1
Please check this url https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=f9bced508d1bfc77aacd8b5826aa6a38
For PostgreSQL, please check this url https://dbfiddle.uk/?rdbms=postgres_11&fiddle=1555612e72404eddc820c254c708304a
I'm fairly new to MySQL, and trying to understand the many-to-many relationship since these examples can popup in interviews
There are 3 tables, and since a Student can have many courses and a Course can have many students, this is a Many-to-Many relationship right?
The tables are
Student- has student ID, name, date of birth, and department.
Courses- Has ID, Name of course
Student_Courses- Has student_id, course_id
How would I display these 2 questions-
1) Given a studentID, return all the names of the courses the student is taking
2) Return the name of students who is taking X amount of courses or more (Ex. 4 or more courses).
Im trying to write queries on these, but I'm stuck...
In the case of selecting all of the courses for a given student ID you could try the following, which will return one row for each Course a Student is associated with.
select
s.name as StudentName,
c.name as CourseName
from `Student` as s
inner join `Student_Course` as sc on (sc.student_id = s.ID)
inner join `Course` as c on (c.ID = sc.course_id)
where
(s.`ID` = 'given_Student_ID_here')
;
As for selecting a list of the names of Students taking N or more courses, for this you might use an aggregating sub-select as a WHERE clause in which we reference one of the outer tables (i.e. [Student]) so that the result of the aggregation is personalised per Student record:
select
s.name as StudentName
from `Student` as s
where
(
(
select count(*)
from `Student_Course` as sc
inner join `Course` as c on (c.ID = sc.course_id)
where (sc.student_id = s.ID)
) >= 4
)
;
You might also consider an alternative approach to this second problem by using the GROUP BY and HAVING clauses:
select
s.name as StudentName
from `Student` as s
inner join `Student_Course` as sc on (sc.student_id = s.ID)
inner join `Course` as c on (c.ID = sc.course_id)
group by
s.name
having
count(*) >= 4
;
Table instructor: ID, name, dept_name, salary
Table student: ID, name, dept_name, tot_cred
Table advisor: s_ID, i_ID which contains student id and instructor id for the two table.
I need to find all the instructor and student's name where the department of the advisor is CComp.Sci
I can find all the id of the instructor and student whrer the intructor is fom Computer science. And only the name of the students.
But can't figure out both the name at the same time.
I wrote this:
SELECT student.name
FROM student
WHERE student.ID in (SELECT advisor.s_ID
FROM advisor
, instructor
WHERE advisor.i_ID = instructor.ID
and instructor.dept_name = 'Comp.Sci')
The root solution I think you need here is just a simple join between the three tables. But since you need a single list of both student and instructor names, this complicates things. One option is to union together a query which finds the matching students along with a query which finds the matching instructors.
SELECT s.name, 'student' AS type
FROM student s
INNER JOIN advisor a
ON s.ID = a.s_ID
INNER JOIN instructor i
ON a.i_ID = i.ID
WHERE i.dept_name = 'CComp.Sci'
UNION ALL
SELECT DISTINCT i.name, 'instructor'
FROM student s
INNER JOIN advisor a
ON s.ID = a.s_ID
INNER JOIN instructor i
ON a.i_ID = i.ID
WHERE i.dept_name = 'CComp.Sci'
Using "where .. in (..)" will give you bad performance, also it will not allow you to get the data from the table in the where clause.
Here is a solution if you mean to get the result of instructor name side alone with student name.
SELECT S.name AS Student,I.name AS Instructor
FROM Students AS S
JOIN Advisor AS A ON A.s_ID = S.Id
JOIN Instructor AS I ON I.Id = A.i_ID
WHERE I.dept_name = 'Comp.Sci'
*notice that I used alias
** if you want for example to get all students even those who lack instructor use LEFT JOIN
so ... here we are ... it's not a simple question so first read it carefully please ...
these are my tables
the first image is courses table
the second is instructors table
the third one is teaches table
now i want the names of the instructors who are teaching some courses that have 4 credits
i tried this :
SELECT *
FROM teaches
INNER JOIN course ON ( course.course_id = teaches.course_id
AND course.credits =4 )
but it's not complete yet ... i know which courses have 4 credits but i don't know how to make a relation between this query and the table called instructors
SELECT i.name
FROM instructor I
JOIN teaches T
ON I.ID = T.ID
JOIN courses C
ON C.course_id = T.course_id
WHERE C.credits = 4
Another option in simple way...
select * from instructors
where id in ( select distinct id
from teaches
where course_id in ( select distinct course_id
from courses
where credits = 4
)
);
I have four schemas:
takes(ID,course_id,sec_id,semester,year)
student(ID,name,dept_name,tot_credit)
course(course_id,title,dept_name,credits)
department(dept_name,building,budget)
I want to create a query that finds the name and id of each Astronomy student whose name begins with the letter âTâ and who has not taken at least 16 Astronomy courses.
What's the easiest way I could do this?
I already wrote this beginning bit
SELECT name, id
FROM student
WHERE dept_name='Astronomy' AND name LIKE '%T%'
I'm not quite sure how to finish this off.
Any help would be greatly appreciated :)
Here's the result
NAME ID CLASS_TAKEN
-------------------- ----- -----------
Tolle 38279 12
Teo 62268 13
Tolle 93223 13
Tsukamoto 17707 5
Titi 11576 9
Teo 91772 12
Toraichi 50387 11
Tewari 80754 14
Tiroz 64091 14
9 rows selected
I need Teo with the id 91772 and Tewari 80754 to be gone
Given my reading of the requirements and the comments it's pretty clear that the question is not very clear. :-) What you're looking for are students where (total # of courses given by the Astronomy department) - (# of Astronomy courses taken by student) >= 16. So, how do we find these values? First, let's start with the total number of courses given by the Astronomy department. This is pretty simple:
SELECT COUNT(*) AS ASTRONOMY_COURSE_COUNT
FROM COURSE
WHERE DEPT_NAME = 'ASTRONOMY'
Now, the second part is to determine how many courses given by the Astronomy department each student has taken. To do this we need to start with the student, join to the courses the student has taken (the TAKES table), then join to the COURSES table to find out which department each course is part of. Something like the following should do it:
SELECT s.ID, s.NAME, COUNT(*) AS STUDENT_ASTRO_COUNT
FROM STUDENT s
INNER JOIN TAKES t
ON t.ID = s.ID
INNER JOIN COURSE c
ON c.COURSE_ID = t.COURSE_ID
WHERE c.DEPT_NAME = 'ASTRONOMY' AND
s.NAME LIKE 'T%'
GROUP BY s.ID, s.NAME;
OK, now we need to put this together. You've tagged this question for both Oracle and MySQL so I'm going to guess you'll accept valid syntax for either database; thus I'll use Oracle Common Table Expression syntax to pull everything together:
WITH ASTRONOMY_COURSES AS (SELECT COUNT(*) AS ASTRONOMY_COURSE_COUNT
FROM COURSE
WHERE DEPT_NAME = 'ASTRONOMY'),
STUDENT_ASTRO_COURSES AS (SELECT s.ID,
s.NAME,
COUNT(*) AS STUDENT_ASTRO_COUNT
FROM STUDENT s
INNER JOIN TAKES t
ON t.ID = s.ID
INNER JOIN COURSE c
ON c.COURSE_ID = t.COURSE_ID
WHERE c.DEPT_NAME = 'ASTRONOMY' AND
s.NAME LIKE 'T%'
GROUP BY ID)
SELECT s.ID,
s.NAME,
s.STUDENT_ASTRO_COUNT,
a.ASTRONOMY_COURSE_COUNT - s.STUDENT_ASTRO_COUNT AS UNTAKEN_COUNT
FROM STUDENT_ASTRO_COURSES s
CROSS JOIN ASTRONOMY_COURSES a
WHERE a.ASTRONOMY_COURSE_COUNT - s.STUDENT_ASTRO_COUNT >= 16;
Note here that a CROSS JOIN is used to put together the subqueries. This means that all the rows of each subquery are joined to all the rows of the other subquery - but since in this case the ASTRONOMY_COURSES subquery will only return a single row what we're doing is appending the ASTRONOMY_COURSE_COUNT value onto each row returned by the STUDENT_ASTRO_COURSES subquery.
That should at least get you pretty close. Amend as needed.
Not tested on animals - you'll be first! :-)
Share and enjoy.
Do you need to use all tables?
Table department has no links with the student,
Table takes has no links with the student,
Table coursehas no links with the student.
If student lists total credits that are all Astronomy I think this can be used:
select name, id, MAX(tot_credit) as credits
from student
where dept_name='Astronomy' and name like 'T%'
group by name, id
having MAX(tot_credit)<=16
PS - you schema is not good; PK-FK references are missing
Your query will need to reference more tables than just the student table.
Your tables seem be missing some important information, which student has taken which course. There's a table named takes, but there doesn't appear to be any relationship between takes and student.
So first, figure out how to list the students along with the Astronomy courses they have taken. Each row will identify the student and a course.
SELECT s.id AS student_id
, s.name AS student_name
, t.???
FROM student s
JOIN ??? t
ON t.student_id = s.id
WHERE ...
You may also need to include another "join" to an additional table, in order to identify which course a student has taken is an Astronomy course.
To also include students that have not take any Astronomy courses, you can use an outer join, rather than an inner join. (That would mean including the LEFT keyword before JOIN, and relocating predicates from the WHERE clause to the ON clause. (A predicate in the WHERE clause that can only be satisfied by non-NULL values will negate the outer-ness of the join.)
Once you have a query that returns that set (students along with any astronomy courses they've taken), you can then add a GROUP BY clause to "collapse" a set of rows into a single row. (Looks like you want the rows "grouped" by student.)
And then an aggregate function like COUNT() or SUM() can be used to get a count of rows for each group. (If you don't want to count any re-takes of a course (a "duplicate" course for a student) you may be able to make use of the COUNT(DISTINCT t.foo) form.
And then a HAVING clause can be added to the query, to compare the value returned from the aggregate expression to a constant value, to return only rows that satisfy a specific condition.
FOLLOWUP
Assuming:
CREATE TABLE course
( id INT UNSIGNED NOT NULL COMMENT 'PK'
, title VARCHAR(30) NOT NULL COMMENT 'course title'
, dept_name VARCHAR(30) NOT NULL COMMENT 'FK ref dept.name'
, credits DECIMAL(5,2) COMMENT 'credit hours'
, PRIMARY KEY (id)
);
CREATE TABLE student
( id INT UNSIGNED NOT NULL COMMENT 'PK'
, name VARCHAR(30) NOT NULL COMMENT 'student name'
, dept_name VARCHAR(30) NOT NULL COMMENT 'FK ref dept.name'
, tot_credit INT COMMENT '?'
, PRIMARY KEY (id)
);
CREATE TABLE takes
( student_id INT UNSIGNED NOT NULL COMMENT 'FK ref student.id'
, course_id INT UNSIGNED NOT NULL COMMENT 'FK ref course.id'
, sec_id INT UNSIGNED NOT NULL COMMENT '?'
, semester INT UNSIGNED NOT NULL COMMENT '?'
, year INT UNSIGNED NOT NULL COMMENT '?'
, PRIMARY KEY (student_id, course_id, sec_id, semester, year)
, CONSTRAINT FK_takes_course FOREIGN KEY (course_id) REFERENCES course (id)
, CONSTRAINT FK_takes_student FOREIGN KEY (student_id) REFERENCES student (id)
);
Query to get a list of students...
SELECT s.id
, s.name
FROM student s
WHERE s.name LIKE 'T%'
AND s.dept_name = 'ASTRONOMY'
Get list of students along with the courses they've taken, returning the id of the ASTRONOMY courses they've taken...
SELECT s.id AS student_id
, s.name AS student_name
, c.id AS course_id
FROM student s
LEFT
JOIN takes t
ON t.student_id = t.id
LEFT
JOIN course c
ON c.id = t.course_id
AND c.dept_name = 'ASTRONOMY'
WHERE s.name LIKE 'T%'
AND s.dept_name = 'ASTRONOMY'
Collapse the rows to one per student using a GROUP BY, and use aggregate functions to get counts or totals.
SELECT s.id AS student_id
, s.name AS student_name
, SUM(c.credits) AS total_astronomy_credits_taken
, COUNT(c.id) AS count_astronomy_courses_taken
, COUNT(DISTINCT c.id) AS count_distinct_astronomy_courses_taken
FROM student s
LEFT
JOIN takes t
ON t.student_id = t.id
LEFT
JOIN course c
ON c.id = t.course_id
AND c.dept_name = 'ASTRONOMY'
WHERE s.name LIKE 'T%'
AND s.dept_name = 'ASTRONOMY'
GROUP
BY s.id
, s.name
To omit rows from this resultset, add a HAVING clause. For example, to exclude rows where total_astronomy_credits_taken is greater than or equal to 12...
HAVING total_astronomy_credits_taken >= 12
If you want the rows returned in a certain sequence, specify that in an ORDER BY clause
ORDER BY s.id
If you want to replace NULL values from the aggregates with zeroes, you can warp the aggregate expression in an IFNULL(foo,0) function, e.g.
, IFNULL(COUNT(c.id),0) AS count_astronomy_courses_taken
Try this :
select a.name, a.id, count(b.ID) as class_taken
from student a inner join takes b
on a.ID = b.ID
inner join course c
on b.course_id = c.course_id
where a.dept_name='Astronomy' and substring(a.name,1,1) = 'T'
group by a.name, a.id
having count(b.ID) < 17