I have 3 tables:
Student (Id, Name, Country)
Course (CrsCode, CrsName, Type, Instructor)
Results(Id, CrsCode, Grade)
I have to solve below q's by using SQL query. Id and CrsCode are key fields in every table. The Type field specifies the course type, e.g. MATH, STAT, SYSC, TTMG, ELEC, etc.
Find the Id of students who take TTMG or SYSC course.
Find the Id of students who take every course.
Find the id of students who take every TTMG course or every SYSC course.
Below are the sample data for part 3. 1st image is the Course Table and 2nd image is the Results table
I am able to solve the 1st question by using the following SQL query: SELECT R.ID FROM RESULTS R JOIN COURSE C ON C.CRSCODE = R.CRSCODE WHERE C.TYPE="TTMG" OR C.TYPE ='SYSC
For the 2nd question, I believe we have to again relate 2nd (Course) and 3rd (Results) table in order to get the result. We have to relate a specific case here. We have to consider a case that there is one specific student who is taking all courses(CrsCode) and we have to find the id of that student.
I believe the query will still be the same as in question 1 but this time there will be little bit changes:
SELECT R.ID FROM RESULTS R JOIN COURSE C
I am not including anything after COURSE C because I am not sure the answer after that. Any pointers will be highly appreciated.
Find the Id of students who take every course.
Assuming course table contains all the courses a student can take, you can group by the id column in the results table and check if the count is equal to the row count in course table.
SELECT ID
FROM RESULTS
GROUP BY ID
HAVING COUNT(DISTINCT CRSCODE) = (SELECT COUNT(*) FROM COURSE)
Edit: Based on OP's comment
Find the id of students who take every TTMG or SYSC course
SELECT r.id
FROM course c
JOIN RESULTS r on c.CRSCODE=r.CRSCODE
GROUP BY r.ID
HAVING COUNT(case when type = 'SYSC' then r.CRSCODE end) = (SELECT COUNT(*) FROM COURSE WHERE type = 'SYSC')
OR COUNT(case when type = 'TTMG' then r.CRSCODE end) = (SELECT COUNT(*) FROM COURSE WHERE type = 'TTMG')
Sample Demo
Related
The question asked is as following:
Write a query that shows a student's transcript. The query should output columns:
Student's Name
Course Title
Numerical Grade
For extra credit list the grade as a letter instead of a number.
The 3 relevant tables are:
registration
which contains the columns
Section_ID / Student_ID / Grade(this is numerical using the 4 point GPA system with no decimals)
student
which contains the columns
ID / Name / Email
course
which contains the columns
ID / Title / Description / Units
The best I could come up with was:
select name, Grade, Title
from SELECT * FROM
(
student
join registration
on registration.Student_ID = student.ID
join course on course.ID = registration.Section_ID
) as transcript group by student ;
This gave me 1064 syntax error, and I'm not sure why. Trying a nested select statement with just 2 of the tables in question worked, don't know why the select from the triple join is rejected.
As for the extra credit portion, I'm not sure what to do besides running an update table statement on the grades column and setting 1,2,3,4 to D, C, B, A.
Your select statement has some syntax issue. The query should be as below. You need to use JOIN properly to establish relation between two tables using Relational Key column.
SELECT name, Grade, Title
FROM Student A
INNER JOIN registration B B.Student_ID = A.ID
INNER JOIN Course C C.ID = B.Section_ID
To get Results per student, Please apply a filter end of the script as-
WHERE A.ID = N --Put Student ID Here.
I have a list of persons in a table. I then have another table where I correlate each person to one or more groups. Some persons have only one entry in the groups table but some have multiple.
I am now trying to SELECT list of persons that are in two specific groups. Person must be in BOTH groups in order to qualify.
My table with the basic information on the persons is base and the table with the group correlation is groups_registration. In fact I also have a third table where the groups names and further information are stored but it is not required for this query.
The groups I am trying to gather in this example are 4 and 11.
What I tried initially was:
SELECT base.*, groups_registration.person_id, groups_registration.group_id
FROM base
INNER JOIN groups_registration
ON base.id = groups_registration.person_id
WHERE (groups_registration.group_id = '4' AND groups_registration.group_id = '11')
ORDER BY base.name
This did not get my any response, I assume because no single row contains both group_id = 4 and group_id 11.
I have been searching through stackoverflow with no joy. Do you guys have any ideas?
Obviously, no row has both values. Use group by:
SELECT gr.person_id, groups_registration.group_id
FROM groups_registration gr
WHERE gr.group_id IN (4, 11)
GROUP BY gr.person_id
HAVING COUNT(DISTINCT gr.group_id) = 2;
I'll let you figure out how to join in the additional information from base.
Notes:
Use table aliases to make it easier to write and read queries.
Presumably, the ids are numbers. Compare numbers to numbers. Only use single quotes for date and string constants.
IN is better than long chains of OR/=.
You can use joins as shown below:
SELECT A.*, B.person_id, B.group_id
FROM base A
INNER JOIN
(SELECT gr.person_id, groups_registration.group_id
FROM groups_registration gr
WHERE gr.group_id IN (4, 11)
GROUP BY gr.person_id
HAVING COUNT(DISTINCT gr.group_id) = 2) B
ON A.id = B.person_id;
This will give you all the desired fields.
I have 2 tables: contracts_main_list and contracts_detail.
In contracts_main_list I have columns:
user_id
contract_id
and in contracts_detail:
contract_id
other columns with data
I need to select all the rows from the table contracts_main_list WHERE user_id = some number.
From these rows I need to get the list of contract numbers (from column contract_id) and according to them select rows corresponding to each of the contract number from the list. So something like:
WHERE contracts_detail.contract_id = contracts_main_list.contract_id
The contract_ids are probably gonna be unique, but in case there is some kind of error and there will be more rows with the same contract_id in either of the tables, I need to select only one row (so probably using DISTINCT) and select the latest record (both tables have a column id as a primary key)
Also if there is no row in contracts_detail matching with the contract_id to the contract_id of the first table contracts_main_list it should skip the row. But I guess the condition:
WHERE contracts_detail.contract_id = contracts_main_list.contract_id
already covers it.
I hope I made it clear enough. What I am trying to do in real life is show list of contracts with all the relevant data belonging to the user.
To sum this up, I need to find all the contracts belonging to the user and select the rows with details about each contract and finally get the data from the contracts_detail table as a result.
Here is the result you're looking for:
SELECT CD.*
FROM (SELECT C2.contract_id
,MAX(C2.id) AS last_main_list_id
,MAX(CD2.id) AS last_contracts_detail_id
FROM contracts_main_list C2
INNER JOIN contracts_detail CD2 ON CD2.contract_id = C2.contract_id
GROUP BY C2.contract_id) L
INNER JOIN contracts_main_list C ON C.id = L.last_main_list_id
AND C.user_id = ?
INNER JOIN contracts_detail CD ON CD.id= L.last_contracts_detail_id
This query use a subquery for the FROM because of the following indication you provided:
The contract_ids are probably gonna be unique, but in case there is
some kind of error and there will be more rows with the same
contract_id in either of the tables, I need to select only one row
If you're sure that the contract_id are unique, here is the same query without this check on contract_id:
SELECT CD.*
FROM contracts_main_list C
INNER JOIN contracts_detail CD ON CD.contract_id = C.contract_id
WHERE C.user_id = ?
Hope this will help you.
I have 2 tables, tbl_students & tbl_inv. The student table holds all information for students. I am creating an invoicing system to create and keep records for invoices (monthly) for the students. The tbl_inv can have multiple invoices for a single student but with a different date. I am trying to create an array which will list all the students with the latest invoice, total and status ordered by the newest invoice date at the top. I am fairly new to programming with mysql and php, so my apologies if my question sounds silly. This is what I have for the query.....
$query = "SELECT * FROM tbl_student
LEFT JOIN tbl_inv ON tbl_student.sid = tbl_inv.inv_sid
GROUP BY tbl_student.sid
ORDER BY tbl_inv.inv_date DESC";
This creates an array which has one line per student but doesn't display the latest invoice date and details.
If anyone can help I would be much appreciated :-)
(Addition pull from direct comments to existing answer)
This is the final query that works..
SELECT
S.*,
TI2.*
FROM
tbl_student S
LEFT JOIN ( SELECT
TI.inv_sid,
MAX(TI.inv_id) LatestInvoice
FROM
tbl_inv TI
GROUP BY
TI.inv_sid ) PreQuery
ON S.sid = PreQuery.inv_sid
LEFT JOIN tbl_inv TI2
ON PreQuery.inv_sid = TI2.inv_sid
AND PreQuery.LatestInvoice = TI2.inv_id
ORDER BY
TI2.inv_id ASC
I have students link with each other my using a field called f_link on the student table. If a student has a family member linked to them the f_link field shows the master id no. If there is no family link the field just shows a 0. With my invoicing system I am creating an invoice for a student and any family member linked to them. The current query will display no data for invoices for the family member, but they have been invoiced. I want to narrow this query down to only display students who have 0 in the f_link field.
Keep looking and learning querying... formatting and readability is a big plus for future maintenance. For this type of problem, ask what is the FIRST thing you need... in your case, on a per-student basis, what is the last invoice they had (regardless of the data).
select
TI.inv_sid,
MAX( TI.inv_date ) LatestInvoiceDate
from
tbl_inv TI
group by
TI.inv_sid
The above will give you one piece of the puzzle, and that is how many complex queries get built. From this, you then want the student's name, and invoice details about this most recent invoice. To do, the above query will be used in the next phase... in this case, it will get an "alias" for its result set to get the rest of the details.
select
S.*,
TI2.*
from
tbl_Student S
LEFT JOIN ( select
TI.inv_sid,
MAX( TI.invoicenumber ) LatestInvoiceNumber,
count(*) totalInvoicesForStudent,
sum( TI.Total ) as TotalAllInvoices,
sum( TI.Total - TI.AmountPaid) as OutstandingBalances
from
tbl_inv TI
group by
TI.inv_sid ) PreQuery
on S.sid = PreQuery.inv_sid
LEFT JOIN tbl_inv TI2
on PreQuery.inv_sid = TI2.inv_sid
AND PreQuery.LatestInvoiceNumber = TI2.invoiceNumber
where
s.F_Link = 0
order by
TI2.inv_date desc
So, to clarify above query
For EVERY Student (table listed first),
do a LEFT JOIN (all students regardless of ever yet having an invoice) to the "PreQuery" result set that has all students with their most recent invoice date).
If such an invoice record WAS found, do another LEFT JOIN to the invoice table AGAIN, but this time on the PreQuery "student id" and the "LatestInvoiceDate" determined for that user to the original invoice table.
Once those are all joined together, get all the fields from both the student table and the SECOND instance (TI2) invoice table for the invoice details.
Now, if you want ONLY students who HAD A MINIMUM of at least 1 invoice, just leave as "JOIN" instead of "LEFT JOIN".
I have a table that tracks attendance in a course. The columns are the courseid, lesson, personid, and date. I have a query (below) that extracts the earliest date a person appears along with the associated course, lesson, and personid. This is used to determine when a person started a particular course and ensure they started with the first lesson. This works fine, but where I am stuck is running this query per course. For example, finding the first date each person in a particular course started it rather than for every course. Right now I am just running the more general query and filtering it in the biz layer.
I obfuscated this a bit so forgive any typos:
select a.courseid,
a.lesson,
a.personid,
a.thedate
from (select personid,
min(thedate) as earliestdate
from attendance
group by personid) as x
inner join attendance as a on (a.personid = x.personid and a.thedate = x.thedate)
Just group over person_id, course in the inner query:
select a.courseid, a.lesson, a.personid, a.thedate
from (
select personid, courseid, min(thedate) as earliestdate
from attendance
group by personid, courseid
) as x
inner join attendance as a
on (a.personid = x.personid and
a.thedate = x.thedate and
a.courseid=x.course_id)
I have a small doubt here. Currently all the information is maintained in single data object/table. How would it be if we have different data model like below...?
Objext1:
Course table: Course details having lession with a relation
Student table: Contains student details.
Will the querying would be simplified in this way....?
Sorry if anything sounds immatur...
Regards,
UDAY