MYSQL How to input externally calculated value into row - mysql

I'm having some issues with this MySQL query. I've got two tables, one that has a list of all the "Leaders of the Opposition"(People elected into office) with the date that they were elected. And I've got another table of all the people they've been married to, and the year they got married in.
I'm trying to make a query that returns all the Leaders of the Opposition ordered by their appointment date with their current spouses name at the time and the date of their marriage.
Here is some practice data of just one leader, dates changed a bit to fit the sort of problem I'm trying to solve.
TABLE ONE:
Leader_of_Opposition------Date Elected
Beazley K C, 1996-03-19
Beazley K C, 2005-01-28
TABLE TWO:
Leader_of_Opposition----Spouses's Name----Year Married
Beazley K C, Mary Ciccarelli, 1974
Beazley K C, Susie Annus, 2004
-
And I'm trying to get it to something like this:
Leader_of_Opposition------Date Elected------Spouses's name--------Year Married
Beazley K C, 1996-03-19, Mary Ciccarelli, 1974
Beazley K C, 2005-01-28, Susie Annus, 2004
-
So far I've got the basics of:
SELECT opposition.leader_name, opposition.time_begin, opposition_marriage.spouse_name, opposition_marriage.year_married'
FROM opposition, opposition_marriage
AND opposition.leader_name=opposition_marriage.leader_name
ORDER BY opposition.time_begin
But it gives me results where the leaders are mentioned multiple times for each marriage. And I can't figure out the syntax to search the other table then place that value into the row.
Any help would be extremely appreciated, been banging my head up against this one for a while now.
Thanks in advance.

I think this is going to be easiest with correlated subqueries. Alas, though, your tables do not have unique identifiers for each row.
SELECT o.leader_name, o.time_begin,
(select om.spouse_name
from opposition_marriage om
where o.leader_name = om.leader_name and om.year_married <= year(o.date_elected)
order by om.year_married desc
limit 1
) as spouse_name,
(select om.year_married
from opposition_marriage om
where o.leader_name = om.leader_name and om.year_married <= year(o.date_elected)
order by om.year_married desc
limit 1
) as year_married
FROM opposition o
ORDER BY o.time_begin;
This handles as many marriages as you like.
Now some comments:
It seems really strange to have a table only of marriages for the opposition leaders and not for all politicians.
The granularity is at the level of a "year", so a leader married in the same year after s/he takes office counts as being married to that spouse.
You do not have a "marriage end date", so a divorced or widowed partner would be considered current until the next marriage.
As I mention in the beginning, you should have a unique identifier for each row.

Related

sql get all available people that are not booked on a particular date and time

I'm struggling with an SQL query.
I am building a booking system for a ski resort and in my database I have instructors and sessions. A session can have an instructor, and it has a date and startTime and endTime.
In order to add a session, I want to get all available instructors for a chosen time and date. In other words, all instructors who don't have a booking on that date and at that time.
Table example:
e.g
instructors: i1, i2, i3, i4, i5, i6, i7, i8
sessions:
Instructor | date | start | end |
**i1** **2017-05-03** **14:30:00** **15:30:00**
**i2** **2017-05-03** **14:30:00** **15:30:00**
**i3** **2017-10-03** **10:30:00** **11:30:00**
**i4** **2017-05-03** **10:30:00** **11:30:00**
**i1** **2017-11-03** **14:30:00** **15:30:00**
Then for input date='2017-05-03' and start='14:30' and end='15'30' i want to get
i3,i4,i5,i6,i7,i8
Figured out that I need to left join session to instructors, group by instructor id and then eliminate those ids that have a field in the group with the selected
inputs. However, for the GROUP BY clause, i have to use an aggregate function and i don't know which one could apply here.
SirWinning's self-answer looks like it should work, but my version below removes some parts which weren't required.
select *
from instructor
where id not in
(select instructorid
from Session
where date='2017-03-19' and starttime<='15:30:00' and endtime>='14:30:00')
This code will find any instructors who aren't booked for a session which overlaps the 14:30-15:30 window on the relevant date.
If that's what's wanted, then you're good to go. Of course it doesn't follow that the instructor is "really available". There could be other things which affect their availabilty (working hours, annual leave etc), so you'll need to ensure that there are things in place to handle such things.
Note also, that this code will prevent an instructor appearing available for "back to back" bookings. If you want to allow a booking to start at 14:30 when another one ends at that time, you'll need to change the <= and >= to < and >.
using not exists()
select *
from instructors i
where not exists (
select 1
from sessions s
where s.instructor = i.id
and s.date = '2017-05-03'
and s.start = '14:30'
and s.end = '15:30'
)
So I tried this query and apparently it works(at least for my test case)
Can anybody take a look and tell me if it looks correct?
select *
from instructor
where id in
(select id
from instructor
group by id
having id not in
(select distinct(instructorid) from Session
where date='2017-03-19' and starttime<='15:30:00' and endtime>='14:30:00') )

Relational Database Logic

I'm fairly new to php / mysql programming and I'm having a hard time figuring out the logic for a relational database that I'm trying to build. Here's the problem:
I have different leaders who will be in charge of a store anytime between 9am and 9pm.
A customer who has visited the store can rate their experience on a scale of 1 to 5.
I'm building a site that will allow me to store the shifts that a leader worked as seen below.
When I hit submit, the site would take the data leaderName:"George", shiftTimeArray: 11am, 1pm, 6pm (from the example in the picture) and the shiftDate and send them to an SQL database.
Later, I want to be able to get the average score for a person by sending a query to mysql, retrieving all of the scores that that leader received and averaging them together. I know the code to build the forms and to perform the search. However, I'm having a hard time coming up with the logic for the tables that will relate the data. Currently, I have a mysql table called responses that contains the following fields,
leader_id
shift_date // contains the date that the leader worked
shift_time // contains the time that the leader worked
visit_date // contains the date that the survey/score was given
visit_time // contains the time that the survey/score was given
score // contains the actual score of the survey (1-5)
I enter the shifts that the leader works at the beginning of the week and then enter the survey scores in as they come in during the week.
So Here's the Question: What mysql tables and fields should I create to relate this data so that I can query a leader's name and get the average score from all of their surveys?
You want tables like:
Leader (leader_id, name, etc)
Shift (leader_id, shift_date, shift_time)
SurveyResult (visit_date, visit_time, score)
Note: omitted the surrogate primary keys for Shift and SurveyResult that I would probably include.
To query you join shifts and surveys group on leader and taking the average then jon that back to leader for a name.
The query might be something like (but I haven;t actually built it in MySQL to verify syntax)
SELECT name
,AverageScore
FROM Leader a
INNER JOIN (
SELECT leader_id
, AVG(score) AverageScore
FROM Shift
INNER JOIN
SurveyResult ON shift_date = visit_date
AND shift_time = visit_time --depends on how you are recording time what this really needs to be
GROUP BY leader ID
) b ON a.leader_id = b.leader_id
I would do the following structure:
leaders
id
name
leaders_timetabke (can be multiple per leader)
id,
leader_id
shift_datetime (I assume it stores date and hour here, minutes and seconds are always 0
survey_scores
id,
visit_datetime
score
SELECT l.id, l.name, AVG(s.score) FROM leaders l
INNER JOIN leaders_timetable lt ON lt.leader_id = l.id
INNER JOIN survey_scores s ON lt.shift_datetime=DATE_FORMAT('Y-m-d H:00:00', s.visit_datetime)
GROUP BY l.id
DATE_FORMAT here helps to cut hours and minutes from visit_datetime so that it could be matched against shift_datetime. This is MYSQL function, so if you use something else you'll need to use different function
Say you have a 'leader' who has 5 survey rows with scores 1, 2, 3, 4 and 5.
if you select all surveys from this leader, sum the survey scores and divide them by 5 (the total amount of surveys that this leader has). You will have the average, in this case 3.
(1 + 2 + 3 + 4 + 5) / 5 = 3
You wouldn't need to create any more tables or fields, you have what you need.

ORDER BY proirity with specific value

I have a table with a column named role and values are as follow:
Scientific staff
PostDocs
Supporting staff
PNUT
Visiting researchers
Secretary
Ph.D. students
Students
Other
I want to use ORDER BY in such a way that Scientific staff comes first. At the moment when I do a query like this, the fields which are Ph.D. students will be returned first (Well because at the moment no row in database has a field with Other in it). Is there a way to achive this using mysql only or should I modify the returned values manually? If so, can you please tell me how?
SELECT * FROM members ORDER BY role
You can do it without an additional table and join, just do:
SELECT * FROM members
ORDER BY
CASE role
WHEN 'Scientific staff' THEN 1
WHEN 'PostDocs' THEN 2
WHEN 'Supporting staff' THEN 5
WHEN 'PNUT' THEN 6
WHEN 'Visiting researchers' THEN 4
WHEN 'Secretary' THEN 3
WHEN 'Ph.D. students' THEN 8
WHEN 'Students' THEN 7
WHEN 'Other' THEN 9
ELSE 10
END
As it is currently implemented, you cannot order by in such a way that Scientific Staff is first, because doing an Oder By sorts it in order of the item in question (in your case, alphabetically it appears by role).
Now, the easy solution to this is to build out a sort priority table with those values in it, assign a numeric priority, then sort by the priority. Let me explain that a little better because it can be confusing:
You make a second table, listing each of these roles, and in a second column give those roles a priority that they will be displayed by.
TABLE:
Role | Priority
Scientific Staff | 1
Ph.D Students | 2
Other | 3
(etc)
You can then do something like this (pseudo-MySQL):
select members.role from members
inner join priority
on members.role = priority.role
order by priority.priority
that will give you the role field from the members table, ordered by the priority you set on the priority table. Since it is an inner join, anyone without a role will not display.

How to perform this MySQL query given this relation diagram

I have the following relation diagram where arrows represent Foreign Keys. The word in the blue is the table name and the words below are column names.
My question is how I could extract the following data from this table:
-what is the GPA of the student with ID=1?
-what are the average GPAs for students by department?
Given that: there are only
five letter grades with values A=4, B=3, C=2, D=1, and F=0, and GPA is the sum of
course credits x course grade value divided by total credits x 4. (so takes.grade is an int from 0-4 inclusive).
I have been trying to figure this out for hours with no avail. Could anyone steer me in the right direction?
Thanks for any help.
Ok, I've actually had to do this for a client over 15 yrs ago, and did for the entire database of all students, not as difficult once you have the pieces.
Without your exact queries as you want guidance.
Start with a single query that pulls data into a TEMPORARY table
CREATE TEMPORARY TABLE AllStudentsCourses
SELECT blah... from blah... join blah.. where... order by ...
A list of all classes a person has signed up for, and while you are at it, have columns computed at the PER-CLASS BASIS the grade earned A-F. You'll also need the credit hours of the class too as that is basis of computing a GPA.
a 3 hour course with an A gets 3 cr hrs towards GPA.
a 6 hour course with an A gets 6 cr hrs towards GPA.
a 6 hour course with a B gets LESS weighted value towards GPA
and you'll need to roll aggregates up.
Now, once you have all the classes a student attempted, you'll need to compute the per-class as sample described. If you want to apply that in the first query, do so.
Once you have that, then, you can roll-up the total credit hrs attempted vs credit hrs earned.
Basic math should help you along.
I didn't quite understand how the GPA is calculated, think there is something wrong with your original post. Here's a starting point that may or may not be right:
SELECT avg(t.grade)
FROM takes t
INNER JOIN course c
ON t.course_id = c.course_id
WHERE t.ID = 1;
SELECT c.dept_name, avg(grade)
FROM takes t
INNER JOIN course c
ON t.course_id = c.course_id
GROUP BY c.dept_name

Need help on database designing

I am currently out of idea how to design this table so I would really like some suggestions. Description as follows:
Table will hold 3 exam result.
Exam A: 8 mandatory subject with infinite optional subject.
Exam B: 6 mandatory subject with infinite optional subject.
Exam C: 1 mandatory subject with 4 optional subject.
Feature to keep in mind:
Each subject's result need to be searchable (eg: Find A for Math in Exam A)
Basic total calculation (eg: calculate how many As in Math for Exam A)
Just inserting data I would be able to think of something however when putting the features into the mix, it just won't work.
My last resort is having a single table with: studentid, exam, subjectcode, result. This will work as in searchable and calculable however I have a feeling of a very messy and huge database in the long run.
My current design (given by my friend):
Each subject and its result have its own field. It works but very hard to expand (add more subjects).
Any recommendations?
Possible table structure (leaving out column definitions):
Exam
---------
Exam_ID
Exam_name
number_of_req_subjects
number_of_opt_subjects <---- -1 could be infinite
Subject
-----------
Subject_id
subject_name
exam_subject
------------
exam_subject_id
exam_id
subject_id
required
exam_result
------------
exam_result_id
exam_subject_id
result
To get the number of A's for Math in Exam A:
SELECT count(exam_result_id)
FROM exam_result er, exam_subject es, subject s, exam e
WHERE er.exam_subject_id = es.exam_subject_id
AND es.subject_id = s.subject_id
AND es.exam_id = e.exam_id
AND e.exam_name = 'A'
AND s.subject_name = 'MATH'
(I know using joins would be better than where to join the different tables, but I'm being a bit lazy).
The subjects result being searchable...we don't have enough information. In fact, my answer may be completely off, but is as close as I think I can get it with the given information at the moment. Making something searchable is just a matter of creating a sufficiently useful select statment.