MySQL Query - earn over the average salary - mysql

I am trying to get this query to work. Basically it is getting all people that earn't a degree at Oxford Brookes that now earn a salary over the average salary of the whole database.
I have searched for hours trying to find a solution. Please feel free to offer advice, so that I may learn from this and solve my issue. Thanks
SELECT a.personid,
a.firstname,
a.lastname,
b.placeofstudy,
AVG(c.salary)
FROM person a
INNER JOIN award d
ON a.personid = d.personid
INNER JOIN qualification b
ON d.qualid = b.qualid
INNER JOIN job c
ON a.personid = c.personid
WHERE placeofstudy = 'Oxford Brookes'
GROUP BY a.personid;
This currently produces no errors but does not return the average salary, just each persons current salary.Even when I add 'having c.salary > avg(c.salary)' it refuses to work.

select a.personid, a.firstname, a.lastname, b.placeofstudy, c.salary, (select avg(salary) from job) as AvgSalary
from person a
inner join award d on a.personid = d.personid
inner join qualification b on d.qualid = b.qualid
inner join job c on a.personid = c.personid
where placeofstudy = 'Oxford Brookes'
and c.salary > (select avg(salary) from job)

You need to use the keyword HAVING.
Try this:
select a.personid, a.firstname, a.lastname, b.placeofstudy, avg(c.salary) AS avgsalary
from person a
inner join award d
on a.personid=d.personid
inner join qualification b
on d.qualid=b.qualid
inner join job c
on a.personid=c.personid
where placeofstudy = 'Oxford Brookes'
group by a.personid, a.firstname, a.lastname, b.placeofstudy
having c.salary > avgsalary

Related

fetch id who have register all adv

There are 3 types of adventures for which I used distinct function in query.
There is only one 1 customer who have booked all types of adventures.
The query i used to fetch the data is:
select c.customerid,c.name
from customer c
inner join booking b
on c.customerid = b.customerid
inner join destination d
on b.destinationid=d.destinationid
inner join adventure a
on d.adventureid=a.adventureid
group by c.customerid
having count(distinct b.bid)=(select count(*) from bid)
or count(distinct a.adventuretype)=(
select count(distinct a.adventuretype)
from adventure
)
You can get the customer ids using aggregation and having:
select b.customerid
from booking b join
destination d
on b.destinationid = d.destinationid join
adventure a
on d.adventureid = a.adventureid
group by b.customerid
having count(distinct a.advtype) = 3;
Or, if you don't want to hardcode the "3", you can use:
having count(distinct a.advtype) = (select count(distinct advtype from adventure)
I'll leave it up to you to add in the customer name (using join, exists, or in).

MySQL Group Join Table

I have below three SQL statement and I want to select out like below, I tried but not success.
Need some
help.
Output:
member_id, balance, firstname, lastname, LastPurchase, LastOrde
SELECT c.member_id
, c.firstname
, c.lastname
, m.balance
FROM member m
, customer c
where m.member_id = c.member_id
order
by m.member_id
SELECT member_id, max(date) as LastPurchase
FROM purchase
GROUP
BY member_id
SELECT member_id, max(date) as LastOrder
FROM ordert
GROUP
BY member_id
You can join these statements -
SELECT c.member_id, c.firstname, c.lastname, m.balance, p.LastPurchase, o.LastOrder
FROM member m
join customer c on m.member_id = c.member_id
left join (SELECT member_id, max(date) as LastPurchase
FROM purchase
GROUP BY member_id) p on p.member_id = m.member_id
left join (SELECT member_id, max(date) as LastOrder
FROM ordert
GROUP BY member_id) o on o.member_id = m.member_id
order by m.member_id
You can join the aggregate queries. The JOIN ... USING syntax comes handy here, since all join column names are the same:
SELECT c.member_id, c.firstname, c.lastname, m.balance, p.last_purchase, o.last_purchase
FROM member m
INNER JOIN customer c USING(member_id)
INNER JOIN (
SELECT member_id, max(date) last_purchase FROM purchase GROUP BY member_id
) p USING(member_id)
INNER JOIN (
SELECT member_id, max(date) last_order FROM order GROUP BY member_id
) o USING(member_id)
ORDER BY c.member_id
Important: your original query uses implicit, old-shool joins (with a comma in the from clause) - this syntax fell out of favor more than 20 years ago and its use is discourage, since it is harder to write, read, and understand.
One of the many benefits of using explicit joins here is that you can easily change the INNER JOINs to LEFT JOINs if there is a possibility that a member has no purchase or no order at all.

Getting result as percentage when using foreign keys

I currently have a DB with 4 table:
Customer
Sale (CustID & RoomID fk)
Room (ManID fk)
Manager
I am trying to get the cities in which the customers reside in as a percentage. However, I only want to show the the customers who made a purchase using a said manager. Currently this comes through as an amount either under or over 100% total.
When this query is isolated to the customer table, the result adds up to 100% correctly, however it does need to be taken from sales using the manager username as a parameter. This is what I currently have:
SELECT
(COUNT(c.city) / (SELECT Count(CustID) FROM Customer) * 100) AS percent, c.city AS City
FROM sale s
INNER JOIN customer c ON s.CustID = c.CustID
INNER JOIN room r ON s.RoomID = r.RoomID
INNER JOIN manager m ON r.ManID = m.ManID
WHERE m.UserName = 'manager123'
GROUP BY c.City;
EDIT:
I wish to add that the CustID may occur more than once within the sales table, additionally, it may be null. Not sure if is required to use distinct when counting.
Having isolated my issue to this, I felt it necessary to mention as I am still unable to exclude these from the result and an incomplete figure (totaling <100% still showing)
Here you go.
SELECT NoCity,COUNT(*)/percent *100 as percentOfCustomerBasedonManager,City
FROM (
SELECT m.UserName,COUNT(c.city) AS NoCity, COUNT(c.CustID) AS percent,c.city AS City FROM
sale s
INNER JOIN customer c ON s.CustID = c.CustID
INNER JOIN room r ON s.RoomID = r.RoomID
INNER JOIN manager m ON r.ManID = m.ManID
GROUP BY c.City ) cityTable WHERE cityTable.UserName = 'manager123'
This may help:
SELECT city, ((city_count)/(customer_count)*100) as Percent
(
SELECT city, COUNT(*) as city_count, customer_count
FROM
(
SELECT distinct c.city
FROM sale s
INNER JOIN customer c ON s.CustID = c.CustID
INNER JOIN room r ON s.RoomID = r.RoomID
INNER JOIN manager m ON r.ManID = m.ManID
WHERE m.UserName = 'manager123'
GROUP BY c.city
) as t1
LEFT JOIN
(
SELECT city as city2, COUNT(*) as customer_count
FROM
(
SELECT c.city, distinct c.CustID
FROM sale s
INNER JOIN customer c ON s.CustID = c.CustID
INNER JOIN room r ON s.RoomID = r.RoomID
INNER JOIN manager m ON r.ManID = m.ManID
WHERE m.UserName = 'manager123'
GROUP BY c.city
) as t2
) as t3 on t1.city=t3.city2
) as master
GROUP BY city
Ok, here is the solution I came to, with a huge thanks to Lim Neo who pointed me in the right direction.
SELECT
round(COUNT(c.city) /
(
SELECT Count(b.CustID)
FROM sale s
INNER JOIN customer c ON s.CustID = c.CustID
INNER JOIN room r ON s.RoomID = r.RoomID
INNER JOIN manager m ON r.ManID = m.ManID
WHERE m.UserName = 'Manager123'
) * 100)
AS percent, c.city AS City
FROM sale s
INNER JOIN customer c ON s.CustID = c.CustID
INNER JOIN room r ON s.RoomID = r.RoomID
INNER JOIN manager m ON r.ManID = m.ManID
WHERE m.UserName = 'Manager123'
GROUP BY c.City;

Is this the right way to join tables to fetch data?

I have a database with the tables:
Student(SID,Name,Surname,Age)
Registration(StudentID,CourseID)
Course(CID,Name,Cost)
I would like to extract only the name of the courses with students younger than 20. Will the query below do just that?
SELECT C.NAME
FROM Course C
INNER JOIN Registration
INNER JOIN Student S
WHERE CID = CourseID
AND SID = StudentID
AND Age < 20
GROUP BY C.NAME
I would also like to extract the number of students in each course having students younger than 20. Is it correct to do it as below?
SELECT count(S.NAME)
,C.NAME
FROM Student S
INNER JOIN Course C
INNER JOIN Registration
WHERE Age < 20
AND CID = CourseID
AND SID = StudentID
GROUP BY C.NAME
You are missing the ON part for the join otherwise it would just be a CROSS JOIN.
Your first query should look like this if you want just a distinct list of student names:
SELECT DISTINCT C.NAME
FROM Course C
INNER JOIN Registration R ON C.CID = R.CourseID
INNER JOIN Student S ON R.StudentID = S.SID
WHERE Age < 20
Your second query shouldn't really have the C.Name in the select if you want to get just a count unless you want a count of how many students have that name.
SELECT count(*)
FROM Student S
INNER JOIN Registration R ON s.SID = R.StudentID
INNER JOIN Course C ON c.CID = R.CourseID
WHERE Age < 20
GROUP BY C.NAME
First join these tables, then group by Course's PK(CID), Add the HAVING condition to filter the course which has students younger than 20.
Then use Course table to join the result to get the course name and count of students in the course.
SELECT
T1.Name,
T2.StudentCount
FROM
Course T1
INNER JOIN (
SELECT
c.CID,
COUNT(s.SID) AS StudentCount
FROM
Course c
LEFT JOIN Registration r ON c.CID = r.CourseID
LEFT JOIN Student s ON s.SID = r.StudentID
GROUP BY c.CID
HAVING COUNT(IF(s.Age < 20, 1, NULL)) > 0
) T2 ON T1.CID = T2.CID
More correctly, you should move the conditions of the join, to the join statements themselves by including them in the on clause instead of the where. While the results may not change in this instance, if you were to start including outer joins you would encounter difficulties.
SELECT count(S.NAME)
,C.NAME
FROM Student S
INNER JOIN Registration R
ON s.SID = R.StudentID
INNER JOIN Course C
ON c.CID = R.CourseID
WHERE Age < 20
GROUP BY C.NAME
There's a fiddle here showing it in action: http://sqlfiddle.com/#!9/c3b8f/1
Your first query will also produce the results you want, but again, you should move the join predicates to the join itself. Also, you don't need to perform the grouping just to get distinct values, mysql has an expression for that called distinct. So rewritten, the first query would look like:
SELECT DISTINCT C.NAME
FROM Student S
INNER JOIN Registration R
ON s.SID = R.StudentID
INNER JOIN Course C
ON c.CID = R.CourseID
WHERE Age < 20.
Again, the results are the same as what you have already but it is easier to 'read' and will put you in good stead when you move on to other queries. As it stands you have mixed implicit and explicit join syntax.
This fiddle demonstrates both queries: http://sqlfiddle.com/#!9/c3b8f/4
edit
I may have misinterpreted your original question - if you want the total number of students enrolled in a course with at least one student under 19, you can use a query like this:
select name, count(*)
from course c
inner join registration r
on c.cid = r.courseid
where exists (
select 1
from course cc
inner join registration r
on cc.cid = r.courseid
inner join student s
on s.sid = r.studentid
where cc.cid = c.cid
group by cc.cid
having min(s.age) < 20
)
group by name;
Again with the updated fiddle here: http://sqlfiddle.com/#!9/c3b8f/17

Using pseudonym in WHERE clause in MYSQL query

Please don't bite me for this, but I'm new to mysql and I have some problem with using pseudonym in WHERE clause. I thought that it is possible to use pseudonym for aggregate function, defined in the select statement.
Here is my query
SELECT a.name, s.name, COUNT(e.id) as total FROM athletes a
INNER JOIN sports s on s.id = a.sport_id
INNER JOIN events e on s.id = e.sport_id
WHERE total >=2 GROUP BY a.name
But, I catch an error "Unknown column total in WHERE clause".
Could anyone tell me if it is right to do query like this?
You can not use alias in the where clause. You need to use that in having
SELECT
a.name,
s.name,
COUNT(e.id) as total FROM athletes a
INNER JOIN sports s on s.id = a.sport_id
INNER JOIN events e on s.id = e.sport_id
GROUP BY a.name having total >=2
Instead of WHERE total >=2 you can use HAVING (total >= 2 )
HAVING:
SELECT a.name, s.name, COUNT(e.id) as total
FROM athletes a
INNER JOIN sports s on s.id = a.sport_id
INNER JOIN events e on s.id = e.sport_id
GROUP BY a.name, s.name
HAVING (total >= 2 );
Yo can not use an column alias in where clause. you have to use the expression COUNT(e.id) in where clasue or you can use the alias in a having clause:
SELECT a.name, s.name, COUNT(e.id) as total FROM athletes a INNER JOIN sports s on s.id = a.sport_id INNER JOIN events e on s.id = e.sport_id WHERE COUNT(e.id)>=2 GROUP BY a.name
or
SELECT a.name, s.name, COUNT(e.id) as total FROM athletes a INNER JOIN sports s on s.id = a.sport_id INNER JOIN events e on s.id = e.sport_id having total>=2 GROUP BY a.name