I am starting an SQL crash course and I have this problem it's bugging me I can't find a solution and with lockdown I have no one I can ask. It's about conditional expressions. In the problem some people play different instruments and they play in duets occasionally in school. I need to find a query that retrieves a table with name and guitar (yes or no) if they play that instrument. I have to work with the following tables:
Table students
| id | name | grade | gender
+-----+-------------+---------+------
| 1 | John | 12 | M
| 2 | Andrew | 11 | F
| 3 | Abigail | 11 | F
| 4 | Simon | 10 | M
Table duets
| id | idStudent1 | idStudent2 | duetOf
+----+------------+------------+------
| 20 | 1 | 2 | Piano
| 35 | 2 | 4 | Piano
| 36 | 3 | 2 | Drums
| 37 | 4 | 1 | Drums
| 35 | 4 | 2 | Guitar
| 36 | 4 | 2 | Flute
| 37 | 4 | 3 | Piano
Query:
select s.name, Coalesce (d.duets, '(none)')
from students s, duet d
where s.id = d.idStudent1
and s.id = d.idStudeant2
and d.instrument = 'guitar'
Any tips on how I can tackle this kind of problem?
You can do conditional aggregation:
select
s.id,
s.name,
max(case when d.duetOf = 'Piano' then 'Yes' else 'No' end) piano,
max(case when d.duetOf = 'Guitar' then 'Yes' else 'No' end) guitar
from students s
left join duets d
on s.id in (d.idStudent1, d.idStudent2)
group by s.id, s.name
This generates one record for each record in students, with two columns that indicate whether the student belongs to a duet that plays guitar or piano.
If you need to display more columns from the students table, you can add them in both the select and group by clauses.
Check this
select s.name, case when duetOf = 'Guitar' then 'Yes' Else 'No' End as Guitar
from duet d
inner join students s on d.idStudent1 = s.Id or d.idStudent2 = s.Id
Related
So I have these 3 tables:
t_student which looks like this:
STUDENT_ID| FIRST_NAME |LAST_NAME
-----------------------------------
1 | Ivan | Petrov
2 | Ivan | Ivanov
3 | Georgi | Georgiev
t_course which looks like this:
course_id | NAME |LECTURER_NAME
-----------------------------------
1 | Basics | Vasilev
2 | Photography| Loyns
t_enrolment which looks like this:
enrolment_id| student_fk |course_fk | Avarage_grade
-------------------------------------------------------
1 | 1 | 1 |
2 | 3 | 1 |
3 | 4 | 1 |
4 | 2 | 1 |
5 | 1 | 2 | 5.50
6 | 2 | 2 | 5.40
7 | 5 | 2 | 6.00
I need to make 'select' statement and present the number of students per course. The result should be:
Count_students | Course_name
-----------------------------
4 | Basics
3 | Photography
Select all courses from your course Table, join the enrolment table and group by your course id. With count() you can select the number of Students
SELECT MAX(t_course.NAME) AS Course_name, COUNT(t_enrolment.student_fk) AS Count_students
FROM t_course
LEFT JOIN t_enrolment ON t_enrolment.course_fk = t_course.course_id
GROUP BY t_course.course_id;
If you want to select the same student in one course only once (if more then one enrolment can happen) you can use COUNT(DISTINCT t_enrolment.student_fk)
UPDATE
To make it working not only in mySQL I added an aggregate function to the name column.
Depending on the SQL database you are using you will have to add quotes or backticks.
Is this your homework?
select count(*) Count_students, c.name as course_name from t_enrolment e, t_course c group where e.course_fk = c.course_id by c.name
You need a select statement with a join to the couse table (for the Course_name). Group by 't_course'.name to use the COUNT(*) function
this will work:
SELECT COUNT(*) AS Count_students, c.NAME AS Course_name
FROM t_enrolment e
JOIN course c
ON e.course_fk = c.course_id
GROUP BY c.NAME
More information
Count function
Group by
Join
I have two tables:
students
+-------+------+
| id | name |
+-------+------+
| 1 | Bob |
+-------+------+
| 2 | Sam |
+-------+------+
and
courses
+----+------------+---------+--------+
| id | student_id | teacher | period |
+----+------------+---------+--------+
| 1 | 1 | Mr. X | 1 |
+----+------------+---------+--------+
| 2 | 1 | Ms. Y | 2 |
+----+------------+---------+--------+
| 3 | 2 | Mr. X | 2 |
+----+------------+---------+--------+
| 4 | 2 | Ms. Y | 3 |
+----+------------+---------+--------+
And this is the result I need from these two tables:
list of students and period 1 teacher
+------------+------+-----------------+
| student_id | name | period 1 teacher|
+------------+------+-----------------+
| 1 | Bob | Mr. X |
+------------+------+-----------------+
| 2 | Sam | null |
+------------+------+-----------------+
Okay, I need a list of students and the teacher they have for a certain period (in this case, period 1). They may, however, have no teacher listed for that period in the courses table, in which case I want 'null' for that column on that student (as above with 'Sam').
The closest I have is this:
SELECT students.id,students.name,courses.teacher
FROM students
LEFT JOIN courses ON students.id = courses.student_id AND courses.period = '1'
But I only ever get back rows that exist in BOTH tables (in this example, only the 'Bob' student would be returned since 'Sam' has no period 1 teacher.
I feel certain it is something simple, but my Google-fu has failed me thus far.
Can you try this:
SELECT students.id,students.name,courses.teacher
FROM students
LEFT JOIN (select * from courses WHERE courses.period = '1') courses
ON students.id = courses.student_id
if I understand correctly and according to the context is to appear only the student BOB.
Assuming it to be true, replace the LEFT for INNER what will work.
SELECT students.id,students.name,courses.teacher
FROM students
INNER JOIN courses ON students.id = courses.student_id AND courses.period = '1'
I hope it is useful
I need help with SQL query. I have this join table, with 22486 rows.
idPerson are people working on movie, pesonType '1' is actor and '2' is director. I need get director and actor and number of their cooperating on movies.
For example, director idPeroson = 3 work with actor idPerson = 14 on 2 movies.
| idFilm | idPerson | peronType |
+---------+---------+--------+
| 1 | 14 | 1 |
| 1 | 3 | 2 |
| 1 | 34 | 1 |
| 2 | 3 | 2 |
| 2 | 14 | 1 |
+---------+---------+--------+
I'm going crazy from that. Thank you very much. And sorry for bad english
Try this:
SELECT DISTINCT
d.idPerson AS Director,
p.idPerson AS Actor,
(SELECT COUNT(p2.idfilm)
FROM Persons p2
INNER JOIN Persons d2 ON p2.idFilm = d2.idFilm
AND d2.peronType = 2
WHERE p2.peronType = 1
AND p2.idperson = p.idperson
AND d2.idperson = d.idperson ) Counts
FROM Persons p
INNER JOIN Persons d ON p.idFilm = d.idFilm
AND d.peronType = 2
WHERE p.peronType = 1;
SQL Fiddle Demo
This will give you:
| DIRECTOR | ACTOR | COUNTS |
-----------------------------
| 3 | 14 | 2 |
| 3 | 34 | 1 |
A more effective way to have the same good result will be :
SELECT
D.idPerson Director,
P.idPerson Actor,
count(1) NBFilm
FROM Persons D
INNER JOIN Persons P ON D.idFilm = P.idFilm
WHERE P.peronType = 1
AND D.peronType = 2
GROUP BY D.idPerson, P.idPerson
So you will have only one inner join. sub queries in select can be very cost effective.
This will give you the person working on number of films,
select idperson,count(distinct idfilm) NoOfFilms,
case when persontype=2 then 'Director' else 'Actor' end Profession
from table1
group by idperson
SQL_LIVE_DEMO
Sample Output:
IDPERSON NOOFFILMS PROFESSION
3 2 Director
14 2 Actor
34 1 Actor
I have 3 tables:
The first one contains information about persons. The relevant column is the personID.
The second contains exercises a person can do. There are for example 3 exercises with an exID.
The third contains the points a person (personID) reached in an exercise (exID). So each row here stands for an examination a person has taken. But not everyone need to have taken every exam.
What I would like to have is a result with the columns personID, exam_one, exam_two, exam_three, ...(ongoing, depending on how many exams there are). And each row of the result should contain the personID and the points from the respective exam.
For exams not taken there should be NULL or something.
Example for table persons:
personID | Name | ...
-------------------
1 | Max |
2 | Peter |
Example for exercises table:
exID | exName | maxPoints | ...
-------------------------------
1 | exam1 | 20
2 | exam2 | 25
3 | exam3 | 20
Example for points table:
personID (fkey) | exID (fkey) | points
----------------------------------------
1 | 1 | 12.5
1 | 3 | 10
2 | 1 | 5
2 | 2 | 8.5
2 | 3 | 10
Wished result:
personId | exam1 | exam2 | exam3
------------------------------------
1 | 12.5 | NULL | 10
2 | 5 | 8.5 | 10
Is there a way to do this? I use PostgreSQL
You can use something like the following:
select p.personId,
sum(case when e.exname = 'exam1' then t.points end) Exam1,
sum(case when e.exname = 'exam2' then t.points end) Exam2,
sum(case when e.exname = 'exam3' then t.points end) Exam3
from persons p
left join points t
on p.personID = t.personID
left join exercises e
on t.exid = e.exid
group by p.personid
See SQL Fiddle with Demo
My SQL-fu is too weak for this, and I'm not even sure it's possible in a single SQL call.
Given I have the following tables:
PARTNER
+----+--------+
| id | name |
+----+--------+
| 1 | bloggs |
| 2 | jones |
PARTNER MANAGER
+----+--------------+------+
| id | partner_id | name |
+----+--------------+------+
| 1 | 1 | fred |
| 2 | 2 | dave |
COMPANY
+----+--------------------+--------+----------+
| id | partner_manager_id | name | active |
+----+--------------------+--------+----------+
| 1 | 1 | comp1 | true |
| 2 | 1 | comp2 | false |
| 3 | 2 | comp3 | true |
| 4 | 2 | comp4 | true |
| 5 | 2 | comp5 | true |
| 6 | 2 | comp6 | true |
I'd like to output the following in a single SQL call:
+--------------+--------------------+----------------------+
| partner_name | n_active_companies | n_inactive_companies |
+--------------+--------------------+----------------------+
| bloggs | 1 | 1 |
| jones | 4 | 0 |
I can join the three tables using two LEFT JOINs but how I can aggregate the counts (with or without the WHERE clause) is eluding me.
Am I barking up the wrong tree, so to speak?
This gets you most of the way there:
SELECT
partner_manager_id,
SUM(CASE WHEN active THEN 1 ELSE 0 END) AS n_active_companies,
SUM(CASE WHEN active THEN 0 ELSE 1 END) AS n_inactive_companies
FROM COMPANY
GROUP BY partner_manager_id
The rest of your question is basically asking how to join this result to the remaining tables. As you point out, to do this use JOINs.
SELECT
PARTNER.name,
T1.n_active_companies,
T1.n_inactive_companies
FROM
PARTNER
LEFT JOIN PARTNER_MANAGER ON partner_id = PARTNER.id
LEFT JOIN
(
SELECT
partner_manager_id,
SUM(CASE WHEN active THEN 1 ELSE 0 END) AS n_active_companies,
SUM(CASE WHEN active THEN 0 ELSE 1 END) AS n_inactive_companies
FROM COMPANY
GROUP BY partner_manager_id
) T1
ON T1.partner_manager_id = PARTNER_MANAGER.id
select p.name "Partner Name"
, c1.cnt "n_active_companies"
, c2.cnt "n_inactive_companies"
from partner p
, (select partner_manager_id id, count(partner_manager_id) cnt from company where active = 'true' group by partner_manager_id) c1
, (select partner_manager_id id, count(partner_manager_id) cnt from company where active = 'false' group by partner_manager_id) c2
where c1.id = p.id
and c2.id = p.id
select p.name as 'partner_name',
sum(case when active then 1 else 0) as 'n_active_companies',
sum(case when active then 0 else 1) as 'n_inactive_companies'
from COMPANY c
join PARTNER_MANAGER pm on c.partner_manager_id = pm.id
join PARTNER p on pm.partner_id = p.id
group by p.name