SQL select, 3 tables - sql

How can I use select if I have 3 tables?
Tables:
school_subject(ID_of_subject, workplace, name)
student(ID_of_student, firstName, surname, adress)
writing(ID_of_action, ID_of_sbuject, ID_of_student)
I want to write the student's name and surname (alphabetically) who have workplace=home.
Is this possible? And how to alphabetize?
SELECT s.firstName, s.surname
FROM student S, school_subject P, writing Z
WHERE P.workplace = 'home'
AND P.ID_of_subject = Z.ID_of_subject
AND Z.ID_of_student = s.ID_of_student;

SELECT s.firstName, s.surname
FROM student S INNER JOIN writing Z
ON Z.ID_of_student = s.ID_of_student
INNER JOIN school_subject P
ON P.ID_of_subject = Z.ID_of_subject
WHERE P.workplace = 'home'
ORDER BY S.firstName, S.surname // Sort the list

To order alphabetically the result it is possible to use ORDER BY keyword. So your query becomes:
SELECT DISTINCT S.firstName, S.surname
FROM student S, school_subject P, writing Z
WHERE P.workplace = 'home' AND
P.ID_of_subject = Z.ID_of_subject AND
Z.ID_of_student = S.ID_of_student
ORDER BY S.surname, S.firstName
The DISTINCT keyword is necessary, because in writing table there are eventually more tuples given keys ID_of_subject and ID_of_student.
So this is necessary to avoid repeating firstName and surname many times.

Note that each student is identified by ID_of_student, not by firstName and surname, so as #danjok said use DISTINCT if you only want the name and surname.
If you want to select all students that satisfy your requirement (even if two or more students have the same firstName and surname), you should including ID_of_student on SELECT clause:
SELECT S.ID_of_student, S.firstName, S.surname
FROM student S
INNER JOIN writing W ON W.ID_of_student = S.ID_of_student
INNER JOIN school_subject P ON P.ID_of_subject = W.ID_of_subject
WHERE P.workplace = 'home'
ORDER BY S.firstName asc, S.surname asc

Related

'ALL' concept in SQL queries

Relational Schema:
Students (**sid**, name, age, major)
Courses (**cid**, name)
Enrollment (**sid**, **cid**, year, term, grade)
Write a SQL query that returns the name of the students who took all courses.I'm not sure how I capture the concept of 'ALL' in a SQL query.
EDIT:
I want to be able write it without aggregation as I want to use the same logic for writing the query in relational algebra as well.
Thanks for the help!
One way of writing such queries is to count the number of course and number of courses each student took, and compare them:
SELECT s.*
FROM students s
JOIN (SELECT sid, COUNT(DISTINCT cid) AS student_courses
FROM enrollment
GROUP BY sid) e ON s.sid = e.sid
JOIN (SELECT COUNT(*) AS cnt
FROM courses) c ON cnt = student_cursed
This gives course combinations that are possible but haven't been taken...
SELECT s.sid, c.cid FROM students CROSS JOIN courses
EXCEPT
SELECT sid, cid FROM enrollment
So, you can then do the same with the student list...
SELECT sid FROM students
EXCEPT
(
SELECT DISTINCT
sid
FROM
(
SELECT s.sid, c.cid FROM students CROSS JOIN courses
EXCEPT
SELECT sid, cid FROM enrollment
)
AS not_enrolled
)
AS slacker_students
I don't like it, but it avoids aggregation...
SELECT *
FROM Students
WHERE NOT EXISTS (
SELECT 1 FROM Courses
LEFT OUTER JOIN Enrollment ON Courses.cid = Enrollment.cid
AND Enrollment.sid = Students.sid
WHERE Enrollment.sid IS NULL
)
btw. names of tables should be in singular form, not plural

Catch multiple types of data in SQL Server

I have a table (Task) like this:
Task Table
and I need answer like this:
TaskResult
I am doing the first query like this:
select
StudentID, AdmissionID, EnquiryID, EnquiryDetailsID
from
Task
where
TaskUser = 0 and BranchID = 1
If I'm getting studentID then I create second query in loop for searching the student first name and last name.
elseif I'm getting EnquiryID then I create second query in loop for searching the Enquiry first name and last name.
elseif I'm getting AdmissionID then I create second query in loop for searching the Admission guys first name and last name.
elseif I'm getting EnquiryDetailsID then I create second query in loop for searching the EnquiryDetails first name and last name.
So it creates loop in a loop and I get heavy load time on the page.
I need to combine both queries into one query. So page won't be loading.
I only have two elements i.e. taskUser and BranchID.
Please help me!! Thanks in advance !!!
So - it looks like you have an oddly organized task table, and as a result, you're going to have to do mildly weird things to query right. According to your description, a row in the task table contains either a studentId, an admissionId, an enquiryId, or an enquiryDetailId. This isn't an optimal way to do this...but I understand that sometimes you have to get by with what you have.
So, to get the names, you have to join to the source of the names...and assuming they're all over the place, in related tables, you could do something like:
select
t.StudentID,t.AdmissionID,t.EnquiryID,t.EnquiryDetailsID,x.FirstName,x.LastName
from Task t inner join Student s on t.StudentId = s.Id
union all
select
t.StudentID,t.AdmissionID,t.EnquiryID,t.EnquiryDetailsID,x.FirstName,x.LastName
from Task t inner join Admission a on t.AdmissionId = a.Id
union all
select
t.StudentID,t.AdmissionID,t.EnquiryID,t.EnquiryDetailsID,x.FirstName,x.LastName
from Task t inner join Enquiry e on t.EnquiryId = e.Id
union all
select
t.StudentID,t.AdmissionID,t.EnquiryID,t.EnquiryDetailsID,x.FirstName,x.LastName
from Task t inner join EnquiryDetail d on t.EnquiryDetailId = d.Id
...or, you can accomplish the same thing kinda inside-out:
select
t.StudentID,
t.AdmissionID,
t.EnquiryID,
t.EnquiryDetailsID,
x.FirstName,
x.LastName
from
Task t
inner join
(
select 's' source, Id, FirstName, LastName from Student union all
select 'a' source, Id, FirstName, LastName from Admission union all
select 'e' source, Id, FirstName, LastName from Enquiry union all
select 'd' source, Id, FirstName, LastName from EnquiryDetail
) as x
on
( t.StudentId = x.Id and x.source = 's' )
or
( t.AdmissionId = x.Id and x.source = 'a' )
or
( t.EnquiryId = x.Id and x.source = 'e' )
or
( t.EnquiryDetailId = x.Id and x.source = 'd' )
where
t.TaskUser=0 and t.BranchID=1
Use LEFT JOIN with COALESCE like this:
--not tested
select StudentID, AdmissionID, EnquiryID, EnquiryDetailsID,
COALESCE(s.name, e.name, d.name, ed.name) as name, etc.
from Task t
left join student s on s.id = t.studentID
left join Enquiry e on e.id = t.EnquiryID
left join Admission d on d.id = t.AdmissionID
left join EnquiryDetails ed on ed.id = t.EnquiryDetailsID
where TaskUser=0 and BranchID=1

SQL Select entries where none of the entities have a value in a particular column

I have a table of data which has students and their subject results in it. The students will appear multiple times, once for each subject they have a result for.
**tableID,studentID,lastName,firstName,subject,grade**
1,1a,Student1,Name1,English,A
2,1a,Student1,Name1,Maths,A
3,1a,Student1,Name1,Science,A
4,2a,Student2,Name2,English,A
5,2a,Student2,Name2,Maths,B
6,2a,Student2,Name2,Science,A
7,3a,Student3,Name3,English,A
8,3a,Student3,Name3,Maths,A
Using Microsoft Access SQL, how can I select only the students who have received an A for all of their subjects? E.g. In the above table, I only want to select all instances of Student1 and Student3, I don't want Student2 as they have not received all A's.
Get all students with grade A except students with any other grade
SELECT
studentID,lastName,firstName
FROM
(SELECT
studentID,lastName,firstName
FROM
result
WHERE
grade = 'A'
GROUP BY
studentID,lastName,firstName) GradeA
LEFT OUTER JOIN
(SELECT
studentID,lastName,firstName
FROM
result
WHERE
grade <> 'A'
GROUP BY
studentID,lastName,firstName) GradeOther
ON GradeA.studentId = GradeOther.StudentID AND GradeA.LAstName = GradeOther.LastName AND GradeA.FirstName = GradeOther.FirstName
WHERE
GradeOther.StudentID IS NULL
One way is using GROUP BY and HAVING:
select StudentId
from t
group by StudentId
having max(grade) = min(grade) and max(grade) = 'A';
I was able to get the results I want by using a sub-query:
SELECT studentID, lastName, firstName
FROM table
WHERE grade = "A"
AND studentID NOT IN (SELECT studentID FROM table WHERE grade <> "A" GROUP BY studentID)
GROUP BY studentID, lastName, firstName
This seems to exclude all students who received a result other than an A.

Only return results from first table with two joins

I have 3 tables. I need to get lastname, firstname, and employee number from the first table and name from another table.
In order for me to get the name on table s there needs to be a match between the slsrep columns on table s and table sw.
The issues is that I only want to return the rows from the first table (p). There is only 700 records in the first table but it is pulling 900.
Basically, I just want to look at each row in the table p and match the name from table s.
This is what I currently have:
SELECT p.LastName,
p.FirstName,
p.EmpNo,
s.Name
FROM PDDA..PhoneDirectory p
LEFT OUTER JOIN nxtsql..swsmsn sw
ON p.EmpNo = sw.EmpNo
JOIN NxtSQL..SMSN s
ON sw.slsrep = s.slsrep
WHERE sw.statustype = 1
ORDER BY
p.LastName
There are lots of ways to do this. One is to use a sub-select to get s.Name:
SELECT p.LastName, p.FirstName, p.EmpNo, (
SELECT TOP 1 s.Name
FROM NxtSQL..SMSN s
INNER JOIN nxtsql..swsmsn sw
ON sw.slsrep = s.slsrep
WHERE p.EmpNo = sw.EmpNo
AND sw.statustype = 1
) AS Name
FROM PDDA..PhoneDirectory p
ORDER By p.LastName

What is wrong with this database query?

I have the following tables in a database (i'll only list the important attributes):
Person(ssn,countryofbirth)
Parents(ssn,fatherbirthcountry)
Employment(ssn, companyID)
Company(companyID, name)
My task is this: given fatherbirthcountry as input, output the names of companies where persons work whose countryofbirth match the fatherbirthcountry input.
I pretend that the fatherbirthcountry is Mexico and do this:
SELECT name
FROM Company
WHERE companyid = (SELECT companyid
FROM Employment
WHERE ssn = (SELECT ssn
FROM Person
WHERE countryofbirth = 'Mexico');
but it is giving me an error:
>Scalar subquery is only allowed to return a single row.
am I completely off track? Can anybody please help?
The problem is that your subqueries are returning multiple results, so you have to use where in vs. =.
Change where ssn = to where ssn in, and where companyid = to where companyid in.
try using the IN keyword not '='.
try changing your query to this
SELECT name
FROM Company
WHERE companyid IN (SELECT companyid
FROM Employment
WHERE ssn IN (SELECT ssn
FROM Person
WHERE countryofbirth = 'Mexico');
Use:
SELECT c.name
FROM COMPANY c
JOIN EMPLOYMENT e ON e.companyid = c.companyid
JOIN PERSON p ON p.ssn = e.ssn
AND p.countryofbirth = 'Mexico'
You should use In in the where condition since the (SELECT ssn
FROM Person
WHERE countryofbirth = 'Mexico'); may return multiple ssn values.
SELECT name
FROM Company
WHERE companyid = (SELECT companyid
FROM Employment
WHERE ssn IN (SELECT ssn
FROM Person
WHERE countryofbirth = 'Mexico');
Try using IN instead of =
When you write:
select a from T where a = ( select....)
The sub-query must return a single value. In case if it returns multiple values, you get your error.
To solve this we use the IN operator which allows the sub-query to return a set of value (>=0) and your where condition succeeds if a equals any one of those values.
select a from T where a IN ( select....)
See if this works
SELECT c.Name FROM PERSON p
LEFT JOIN Employment e ON p.ssn=e.ssn
LEFT JOIN Company c ON
e.CompanyID=c.CompanyID WHERE
p.countryofbirth=
The error is due to the fact that the one of the two subqueries are returning multiple rows. I would think it likely that you have multiple people born in Mexico for example.
Select Name
From Companies
Where Exists(
Select 1
From Employment
Join Person
On Person.SSN = Employment.SSN
Join Parents
On Parents.SSN = Person.SSN
Where Parents.FatherBirthCountry = Person.CountryOfBirth
And Parents.FatherBirthCountry = #InputParam
And Employment.CompanyId = Companies.CompanyId
)
Ideally use the answer from OMG Ponies using JOINs.
But if you do not like JOINs for whatever reason, then TOP 1 should do the trick for you:
SELECT name
FROM Company
WHERE companyid =(SELECT TOP 1 companyid
FROM Employment
WHERE ssn = ( SELECT TOP 1 ssn
FROM Person
WHERE countryofbirth = 'Mexico');