How can i solve blank spots in a SQL View? - sql

In my sqllite-excercises i have discovered the following problem:
I basically have three different Tables:
Subjects
PRIMARY KEY(ID)
Subject
1
Business
2
IT
3
Sports
Participants
PRIMARY KEY(ID)
Name
semester
1
Meyer
6
2
Smith
4
3
Brown
4
4
White
2
5
Anthonie
2
6
Frankson
2
They are referenced in the Table participants List
SUBJECT.ID
Participant.ID
1
2
1
3
1
5
2
4
2
6
3
1
Now im supposted to create a VIEW that contains: The Participants.ID, Participants.Name and Subjects.Subject so i have a Table that shows the ID, the Name and the Subject the participant is visiting.
So far I did this:
CREATE VIEW[OVERVIEW]AS
SELECT Participants.ID,
Participants.Name,
Subjects.Subject
from Participants
LEFT JOIN Subjects on Participants.ID = Subjects.ID;
As a result i get this:
Participants.ID
Participant.Name
Subjects.Subject
1
Meyer
Business
2
Smith
IT
3
Brown
Sports
4
White
None
5
Anthonie
None
6
Frankson
None
And it makes sense since there are only three Subjects and i Leftjoined 6 Participants.ID on only 3 Subjects.Subject
How can i fill out the blank Subjects? So that the subjects for 4-6 are shown aswell?
I hope you can understand my problem and i declared it good enough.

You can't join Participants to Subjects because they are not directly related, so this ON clause:
on Participants.ID = Subjects.ID
does not make sense because the IDs of participants are not related to the IDs of the subjects.
You have the table ParticipantsList that can be used as an intermediate link between the other 2 tables:
SELECT p.ID, p.Name, s.Subject
FROM Participants p
LEFT JOIN ParticipantsList pl ON pl.Participant_ID = p.ID
LEFT JOIN Subjects s ON s.ID = pl.Subject_ID;
This will return all participants, even if they are not linked to any subject.
If you want only the participants for which there is at least 1 subject in the table ParticipantsList then you can use INNER joins.
For the sample data that you provide in your question in both cases the results are the same.
See the demo.

Related

How both asterisked lines are correct given the SQL statement

A new social network site has the following data tables:
Table users:
id
name
sex
1
Ann
null
2
Steve
m
3
Mary
f
4
Brenda
f
Table friends:
user1
user2
1
2
1
3
2
3
Select data that will be returned by the following SQL query:
SELECT users.name,
COUNT(*) as count
FROM users LEFT JOIN
friends ON users.id = friends.user1 OR users.id = friends.user2
WHERE users.sex = 'f'
GROUP BY users.id,
users.name;
Output:
name
count
Ann
1
Ann
2
Steve
1
Steve
2
Mary
1
Mary
2 **
Brenda
0
Brenda
1 **
The asterisked sections are the correct answers, but I don't quite understand why (Brenda, 1) would be an answer here when (Mary, 2) is also a correct answer.
This is a trap question. The query looks like your are selecting all female users (sex = 'f') and count their friendships. For this a left outer join on the friends table is applied, so we keep all female users, no matter whether they have friendships or not.
But then the query uses COUNT(*), which counts the joined rows. That is 2 for Mary and 1 for Brenda. If we wanted to count friendships, we'd have to count a column of the friends table, e.g. COUNT(friends.user1). Thus the outer joined rows having these columns set to null would be omitted from the count, and we'd get 2 for Mary and 0 for Brenda.

how can I convert this SQL statement with nested IN clauses to a JOIN format

Here are the very simplified versions of my three tables.
Schools_Subjects Table
SchoolId
SubjectId
1
2
5
1
5
6
The above table contains only parent subject IDs.
Subjects Table
SubjectId
Name
ParentSubjectId
1
Science
{NULL}
2
Mathematics
{NULL}
3
Biology
1
4
Physics
1
5
Chemistry
1
6
History
{NULL}
7
Elementary Math
2
8
Calculus
2
Questions Table
QuestionId
Text
SubjectId
1
What is 2 + 2
7
2
Tell me the fastest animal name
3
3
Salt is composed of which two elements
5
4
How to divide 6 apples among 3 students
7
I want to fetch all the questions given a (or multiple) school ID. For example for schoolId:5, I have the below SQL query:
SELECT *
FROM Questions
WHERE SubjectId IN (
SELECT SubjectId
FROM Subjects
WHERE ParentSubjectId IN (
SELECT SubjectId
FROM Schools_Subjects
WHERE SchoolId = 5
)
)
My above query works but I want to change it into a JOIN format query.
I work on SQL Server, but a ANSI-SQL query will be highly appreciated.
If using Mysql:
SELECT Q.*
FROM Questions Q
JOIN (
SELECT S.SubjectId
FROM Subjects S
JOIN Schools_Subjects SS
ON S.ParentSubjectId = SS.SubjectId AND SS.SchoolId = 5
) t1
ON Q.SubjectID = t1.SubjectId
QuestionId Text SubjectId X
1 2 Tell me the fastest animal name 3 NA
2 3 Salt is composed of which two elements 5 NA
Which is the same results produced by your code

Translate sql query on Django

I have two tables: students (that has all the students of a school) and suspensions (all the students that are suspended)
id
name
school_grade
1
Jeff
1
2
Dave
1
3
Susan
2
4
Will
2
5
Peter
3
id
reason
student_id
1
Missed class
1
2
Arrived 20 times late
2
3
Fight
5
So I need to get statistics of which students of different grades are suspended.
So, my query is this.
SELECT school_grade, count(school_grade)
FROM students JOIN suspensions ON students.id=suspensions.student_id
GROUP BY school_grade;
And this query gives me exactly what I want.
school_grade
number of suspension
3
1
1
2
But I don't understand how to make this query on django.
Try:
students.objects.values("school_grade").annotate(Count("suspensions"))
This should work as expected

How to count entries in sql "like in a loop"

First thing, I'm very new to databases so this is probably a very simple question, but I didn't know how to google it or how to give it a good title. I'm using postgres from python, but the problem is to put together the right query.
The scenario is the following. I hava a table with columns: ID, Trial, Subject, Invalid. It comes from a behavioral experiment where many subjects perform a task that is composed of several trials. Their responses can be invalid for different reasons, and depending on the reason there is a different invalidation code (an integer). A valid response has code 0.
------------------------------
ID | SUBJECT | TRIAL | INVALID
------------------------------
1 Peter 1 0
2 Peter 2 0
3 Peter 3 1
4 Peter 4 3
5 Mary 1 3
6 Mary 2 2
7 Mary 3 0
8 Mary 4 2
I would like to do two things (which I'm not sure how to do in an elegant way).
a) For each subject, I would like to know how many responses are in total and how many are valid. Now I'm making a query for each subjects, with the condition, e.g., WHERE Subject='Peter', but I can imagine that there is a more elegant solution.
Sample answer:
Subject Valids Total
Peter 2 4
Mary 1 4
b) For each subjects, I would like to know how many responses were invalid for each of the invalidation codes. Ideally I would get a table like:
Subject Invalid Count
Peter 0 2
Peter 1 1
Peter 2 0
Peter 3 1
Mary 0 1
Mary 1 0
Mary 2 2
Mary 3 1
Query #1: You want one result row per subject, so you group by subject. Use COUNT to count all records for a subject and COUNT in combination with CASE to count conditionally (all valid ones).
select
subject,
count(*) as all_responses,
count(case when invalid = 0 then 1 end) as valid_responses
from mytable
group by subject;
Query #2: Here you want one result row per subject and code, so you group by these two. Then count with COUNT.
select
subject,
invalid,
count(*) as responses
from mytable
group by subject, invalid;
UPDATE: In your updated request you want query #2 to show all subject/code combinations even if they have a count of 0. In order to do this, you'd have to create the set of all valid combinations first and then outer join your response table:
select
s.subject,
c.code,
count(m.invalid) as responses
from subjects s
cross join codes c
left join mytable m on (m.subject = subjects.subject and m.invalid = codes.code)
group by s.subject, c.code;
If you don't have tables for subjects and code (which you should), you can get them from your responses table instead:
select
s.subject,
c.code,
count(m.invalid) as responses
from (select distinct subject from mytable) s
cross join (select distinct invalid as code from mytable) c
left join mytable m on (m.subject = subjects.subject and m.invalid = codes.code)
group by s.subject, c.code;

Oracle SQL generate query

Following is my table schema.
Channel listing table:
CHAN_NUMBER CHAN_NAME CHAN_TYPE
----------- -----------------------------------
1 MTV Music
2 ESPN Sports
3 TNT Movies
4 Fox Movies
5 Fox Sports
customer survey table:
SURV_ID SURV_DATE SURV_FAV_CHAN CUST_NUMBER
---------- --------- ------------- -----------
1 25-NOV-12 1 2
2 24-NOV-12 2 1
3 24-NOV-12 3 3
4 24-NOV-12 4 4
5 24-NOV-12 5 5
6 24-NOV-12 1 6
7 24-NOV-12 2 7
8 24-NOV-12 3 8
9 24-NOV-12 4 9
10 24-NOV-12 5 10
11 24-NOV-12 1 11
I have these two tables that I need to generate a report that lists every channel and a count of how many customers have selected that channel as their favorite.
On oracle database I got up to the point where I am generating a count of each time a channel was selected as a favorite from the SURVEY table. But I can't figure out how to join them to create a list of channels displaying the channel number, the name and the count of customers who chose it as their favorite.
-- my channel table query
SELECT CHAN_NUMBER, CHAN_NAME FROM CHANNEL;
-- here is how I'm generating the couNt
SELECT COUNT(SURV_FAV_CHAN) FROM SURVEY
GROUP BY SURV_FAV_CHAN HAVING COUNT(SURV_FAV_CHAN) > 1;
ANY HELP WOULD BE AWESOME.
Please check this reference * SQLFIDDLE
You said you want list every channel, and count of how many customers have selected that channel as their favourite.
Let's go from nested to outside. Nested query you count number of customers from Survery table grouping by favourite channel. Every channel means, you need to do a LEFT JOIN on Channels table to get all the records.
Query:
(select c.*, s.ct from
channel c
left join
(select count(cust_number) as ct
, surv_fav_chan from survey
group by surv_fav_chan) as s
on c.chan_number = s.surv_fav_chan
;
Results:
CHAN_NUMBER CHAN_NAME CHAN_TYPE CT
1 MTV Music 3
2 ESPN Sports 2
3 TNT Movies 2
4 Fox Movies 2
5 Fox Sports 2
You seem to treat FOX as two channels offering two different types of programmes. So I have left it as it is. If you want to even count customers by channel type then please clarify.
PS: You may ignore the other old table schema in that SQLFIDDLE table sample. NOTE that it is in MYSQL, however this is an ANSI query - so you may apply it to ORACLE as well.
You can try something like this:
SELECT MAX(CH.CHAN_NUMBER), MAX(CH.CHAN_NAME), COUNT(SRV.SURV_FAV_CHAN) FROM SURVEY SRV
LEFT JOIN CHANNEL CH ON CH.CHAN_NUMBER = SRV.SURV_FAV_CHAN
GROUP BY SRV.SURV_FAV_CHAN HAVING COUNT(SRV.SURV_FAV_CHAN) > 1;
And you may want to use SUM(SRV.SURV_FAV_CHAN) if you really need the total amount of customers if I understand you question correctly
Assuming that SURV_FAV_CHAN and CHAN_NUMBER is the relation, use that for your JOIN, so try this:
SELECT CHAN_NUMBER
, CHAN_NAME
, COUNT(DISTINCT SURVEY.CUST_NUMBER) AS FAV_CHANNEL_CNT
FROM CHANNEL
LEFT JOIN SURVEY
ON SURVEY.SURV_FAV_CHAN = CHANNEL.CHAN_NUMBER
GROUP BY CHAN_NUMBER, CHAN_NAME