i have table A in mysql
+-------------------------+
| ID Name Month Salary |
+-------------------------+
| 1 Joe 4 300 |
| 2 Kim 3 100 |
| 3 Moko 2 150 |
| 4 Loli 5 80 |
| 5 Tom 3 400 |
+-------------------------+
how do i get total number of salary based on month and the person who earned max
example
Joe = 4*300 = 1200
Kim = 300
Moko = 300
Loli = 400
Tom = 1200
The output will be : 1200, 2
1200 is the max salary and 2 is people who earned which is Joe and Tom
You can compute all the total salaries in a subquery, then count the number of occurrences of each total value, ordering by the total descending with a LIMIT 1 to restrict to the highest value:
SELECT total, COUNT(*) AS num
FROM (
SELECT Month * Salary AS total
FROM data
) t
GROUP BY total
ORDER BY total DESC
LIMIT 1
Output:
total num
1200 2
Demo on SQLFiddle
try like below using subquery
select max(salary),count(*) from (select name, sum(Month*Salary) as salary
from data group by name
) b where b.salary=
(select max(salary) from
(select sum(Month*Salary) as salary
from data group by name
)b
)
Demo link
SELECT Month*Salary, COUNT(*)
FROM A WHERE Month*Salary = (SELECT MAX(Month*Salary)
FROM A)
The second query will give you the maximum total salary earned and then you can filter the entries in table A with Month*Salary being equal to that amount.
Related
SQL Question:
Write a SQL query to get the nth highest salary from the Employee table (SQL Server)
| Id | Salary |
+----+--------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
For this example, the nth highest salary where n = 2 is 200. If there is no nth highest salary, then the query should return null.
| getNthHighestSalary(2) |
+------------------------+
| 200 |
My code is the following:
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
RETURN (
select distinct a.salary from Employee a, Employee b where
a.id =b.id-n+1 order by a.id desc
limit 1
);
END
My question is: The code works for most of the cases except for the situation when there are multiple same values before the nth place. For example, whe n is 2 and the table is the following. (The expected result should be NULL and my code returns 100. ) So, how can I change my code so that it can work for all situations? Thank you!
+----+--------+
| id | salary |
+----+--------+
| 1 | 100 |
| 2 | 100 |
| 3 | 100 |
+----+--------+
Try this
Select distinct salary
From (
Select salary, dense_rank() over
(order by salary desc) r
from employee
) where r=n
1st 2nd and 3rd highest salary query
SELECT MAX(salary) AS ThirdHighestSalary
FROM emp
WHERE (salary <
(SELECT MAX(salary) AS SecondHighestSalary
FROM emp
WHERE (salary <
(SELECT MAX(salary) AS HighestSalary
FROM emp))))
I have the current table:
+----------+-------+
| salesman | sales |
+----------+-------+
| 1 | 142 |
| 2 | 120 |
| 3 | 176 |
| 4 | 140 |
| 5 | 113 |
| 6 | 137 |
| 7 | 152 |
+----------+-------+
I would like to make a query to retrieve the 3 top salesman, and an "Other" column, that would be the sum of everyone else. The expected output would be:
+----------+-------+
| salesman | sales |
+----------+-------+
| 3 | 176 |
| 7 | 152 |
| 1 | 142 |
| Others | 510 |
+----------+-------+
I am using MySQL, and I am experienced about it, but i can't imagine a way of doing this kind of GROUP BY.
A tried UNION with 2 SELECT, one for the top 3 salesman and another select for the "Others", but I couldn't figure a way of excluding the top 3 from the 2nd SELECT
You can do this by LEFT JOINing your table to a list of the top 3 salesmen, and then grouping on the COALESCEd salesman number from the top 3 table (which will be NULL if the salesman is not in the top 3).
SELECT COALESCE(top.sman, 'Others') AS saleman,
SUM(sales) AS sales
FROM test
LEFT JOIN (SELECT salesman AS sman
FROM test
ORDER BY sales DESC
LIMIT 3) top ON top.sman = test.salesman
GROUP BY saleman
ORDER BY saleman = 'Others', sales DESC
Output:
saleman sales
3 176
7 152
1 142
Others 510
Demo on dbfiddle
Using UNION, ORDER BY, LIMIT, OFFSET AND GROUP BY statements you should do the trick:
SELECT salesman, sales
FROM t
ORDER BY sales DESC LIMIT 3
UNION
SELECT 'Others', SUM(sales)
FROM (SELECT salesman, sales
FROM t
ORDER BY sales DESC LIMIT 3, 18446744073709551615) AS tt;
The big number at the end is the way to apply limit until the end of the table, as suggested here
This is a pain in MySQL:
(select salesman, count(*) as cnt
from t
group by salesman
order by count(*), salesman
limit 3
) union all
(select 'Others', count(*)
from t left join
(select salesman, count(*) as cnt
from t
group by salesman
order by count(*)
limit 3
) t3
on t3.salesman = t.salesman
where t3.salesman is null
);
This should be the fastest one if appropriate indexes are present:
(
SELECT salesman, sales
FROM t
ORDER BY sales DESC
LIMIT 3
)
UNION ALL
(
SELECT 'Other', SUM(sales) - (
SELECT SUM(sales)
FROM (
SELECT sales
FROM t
ORDER BY sales DESC
LIMIT 3
) AS top3
)
FROM t
)
ORDER BY CASE WHEN salesman = 'Other' THEN NULL ELSE sales END DESC
this will work:
select salesman,sales from tablename a where a.salesman in (3,7,1)
union all
select 'others' as others,sum(a.sales) as sum_of_others from tablename a where
a.salesman not in (3,7,1) group by others;
check https://www.db-fiddle.com/f/73GjFXL3KsZsYnN26g3rS2/0
I am in a very complicated problem. Let me explain you first what I am doing right now:
I have a table name feedback in which I am storing grades against course id. The table looks like this:
+-------+-------+-------+-------+-----------+--------------
| id | cid | grade |g_point| workload | easiness
+-------+-------+-------+-------+-----------+--------------
| 1 | 10 | A+ | 1 | 5 | 4
| 2 | 10 | A+ | 1 | 2 | 4
| 3 | 10 | B | 3 | 3 | 3
| 4 | 11 | B+ | 2 | 2 | 3
| 5 | 11 | A+ | 1 | 5 | 4
| 6 | 12 | B | 3 | 3 | 3
| 7 | 11 | B+ | 2 | 7 | 8
| 8 | 11 | A+ | 1 | 1 | 2
g_point has just specific values for the grades, thus I can use these values to show the user courses sorted by grades.
Okay, now first my task is to print out the grade of each course. The grade can be calculated by the maximum occurrence against each course. For example from this table we can see the result of cid = 10 will be A+, because it is present two times there. This is simple. I have already implemented this query which I will write here in the end.
The main problem is when we talk about the course cid = 11 which has two different grades. Now in that situation client asks me to take the average of workload and easiness of both these courses and whichever course has the greater average should be shown. The average would be computed like this:
all workload values of the grade against course
+ all easiness values of the grade against course
/ 2
From this example cid = 11 has four entries,have equal number of grades against a course
B+ grade average
avgworkload(2 + 7)/2=x
avgeasiness(3 + 8)/2 = y
answer x+y/2 = 10
A+ grade average
avgworkload(5 + 1)/2=x
avgeasiness(4 + 2)/2 = y
answer x+y/2 = 3
so the grade should be B+.
This is the query which I am running to get the max occurrence grade
SELECT
f3.coursecodeID cid,
f3.grade_point p,
f3.grade g
FROM (
SELECT
coursecodeID,
MAX(mode_qty) mode_qty
FROM (
SELECT
coursecodeID,
COUNT(grade_point) mode_qty
FROM feedback
GROUP BY
coursecodeID, grade_point
) f1
GROUP BY coursecodeID
) f2
INNER JOIN (
SELECT
coursecodeID,
grade_point,
grade,
COUNT(grade_point) mode_qty
FROM feedback
GROUP BY
coursecodeID, grade_point
) f3
ON
f2.coursecodeID = f3.coursecodeID AND
f2.mode_qty = f3.mode_qty
GROUP BY f3.coursecodeID
ORDER BY f3.grade_point
Here is SQL Fiddle.
I added a table Courses with the list of all course IDs, to make the main idea of the query easier to see. Most likely you have it in the real database. If not, you can generate it on the fly from feedback by grouping by cid.
For each cid we need to find the grade. Group feedback by cid, grade to get a list of all grades for the cid. We need to pick only one grade for a cid, so we use LIMIT 1. To determine which grade to pick we order them. First, by occurrence - simple COUNT. Second, by the average score. Finally, if there are several grades than have same occurrence and same average score, then pick the grade with the smallest g_point. You can adjust the rules by tweaking the ORDER BY clause.
SELECT
courses.cid
,(
SELECT feedback.grade
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS CourseGrade
FROM courses
ORDER BY courses.cid
result set
cid CourseGrade
10 A+
11 B+
12 B
UPDATE
MySQL doesn't have lateral joins, so one possible way to get the second column g_point is to repeat the correlated sub-query. SQL Fiddle
SELECT
courses.cid
,(
SELECT feedback.grade
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS CourseGrade
,(
SELECT feedback.g_point
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS CourseGPoint
FROM courses
ORDER BY CourseGPoint
result set
cid CourseGrade CourseGPoint
10 A+ 1
11 B+ 2
12 B 3
Update 2 Added average score into ORDER BY SQL Fiddle
SELECT
courses.cid
,(
SELECT feedback.grade
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS CourseGrade
,(
SELECT feedback.g_point
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS CourseGPoint
,(
SELECT (AVG(workload) + AVG(easiness))/2
FROM feedback
WHERE feedback.cid = courses.cid
GROUP BY
cid
,grade
ORDER BY
COUNT(*) DESC
,(AVG(workload) + AVG(easiness))/2 DESC
,g_point
LIMIT 1
) AS AvgScore
FROM courses
ORDER BY CourseGPoint, AvgScore DESC
result
cid CourseGrade CourseGPoint AvgScore
10 A+ 1 3.75
11 B+ 2 5
12 B 3 3
If I understood well you need an inner select to find the average, and a second outer select to find the maximum values of the average
select cid, grade, max(average)/2 from (
select cid, grade, avg(workload + easiness) as average
from feedback
group by cid, grade
) x group by cid, grade
This solution has been tested on your data usign sql fiddle at this link
If you change the previous query to
select cid, max(average)/2 from (
select cid, grade, avg(workload + easiness) as average
from feedback
group by cid, grade
) x group by cid
You will find the max average for each cid.
As mentioned in the comments you have to choose wich strategy use if you have more grades that meets the max average. For example if you have
+-------+-------+-------+-------+-----------+--------------
| id | cid | grade |g_point| workload | easiness
+-------+-------+-------+-------+-----------+--------------
| 1 | 10 | A+ | 1 | 5 | 4
| 2 | 10 | A+ | 1 | 2 | 4
| 3 | 10 | B | 3 | 3 | 3
| 4 | 11 | B+ | 2 | 2 | 3
| 5 | 11 | A+ | 1 | 5 | 4
| 9 | 11 | C | 1 | 3 | 6
You will have grades A+ and C soddisfing the maximum average 4.5
So I'm currently using the following bit of SQL to select the closest rank value to the given variable but I'm looking to implement a feature so I can grab the closest rank value but nothing greater than the variable.
Here is my current SQL statement:
SELECT rank, points
FROM `4star`
WHERE arenaID = 6
ORDER BY ABS(rank - $v) ASC
LIMIT 1
$v indicates the PHP variable.
If this was my table:
+---------+----------+
| rank | points |
+---------+----------+
| 1 | 9 |
| 50 | 7 |
| 200 | 6 |
| 5000 | 4 |
| 10000 | 1 |
+---------+----------+
how would I select the closest rank to 3000 that was not greater than 3000? So the row I would get would be 200 => 6?
Try this:
SELECT rank,points
FROM `4star`
WHERE rank <=3000
AND arenaID = 6
ORDER BY rank Desc
LIMIT 1
how would I select the closest rank to 3000 that was not greater than
3000?
Use WHERE to select rows where rank is less than/equal to 3000, then ORDER BY rank descending and LIMIT the results to one row:
SELECT rank
FROM table
WHERE rank <= 3000 AND arenaID = 6
ORDER BY rank DESC
LIMIT 1
I have a table
car
id | person_id | mpg
------------------------
4 | 1 | 50
5 | 1 | 15
6 | 2 | 10
7 | 2 | 28
8 | 3 | 33
I need to get an average of each person's mpg and then an average for the group.
person 1 avg = (50 + 15) / 2 = 32.5
person 2 avg = (10 + 28) / 2 = 19
person 3 avg = 33
group average = 32.5 + 19 + 33 / 3 = 28.1
Is there a query that will do what I need?
SELECT person_id, AVG(mpg) from car group by person_id;
If you want to get an average for the group, you should probably do this:
SELECT AVG(mpg) from car;
Unless you really want to average the averages, which seems a bit dubious to me:
SELECT AVG(average) from (SELECT person_id, AVG(mpg) as average from car group by person_id);
you cannot solve this in 1 query, but you have to use 2 queries or 1 query en solve the overal average in your code
select person, avg(mpg) from cat group by person
SELECT person_id, AVG(mpg) AS mpg_avg FROM car GROUP BY person_id WITH ROLLUP
The WITH ROLLUP-modifier will add a line to the result set where persion_id is NULL and mpg_avg is the average over the whole result set (MySQL >= 4.1.1):
person_id | mpg
------------------
1 | 32.5
2 | 19.0
3 | 33.0
NULL | 27.2