SQL Group by returning wrong results - mysql

I have a salary table in which I am trying to return determine the lowest salary earned and by which industry for each year however despite getting the correct lowest salary earned I am receiving the wrong industry name.
I am aware that it is due to the fact that I have utilized GROUP BY without placing a constraint(?) on it hence it is returning me the wrong value but I am not sure how I can solve it.
SALARY TABLE
salaryID
salaryAmount
salaryYear
industryName (ForeignKey)
Can someone please guide me on the right path?
**(Problem Code)**
SELECT MIN(S.salary), S.industryName, S.salaryYear
FROM salary
GROUP BY S.salaryYear;
**(Attempted solution)**
SELECT S.salary
FROM salary
INNER JOIN
SELECT (min(S1.amount)), S1.year, S1.industryName, S1.salaryId
FROM salary S1
GROUP BY S1.year
ON S.salaryId = S1.salaryId);

Use a proper GROUP BY. Any non-aggregated columns must be included in GROUP BY.
SELECT MIN(amount), year
FROM salary
GROUP BY year
If you want to include industryName,
SELECT amount, year, industryName, salaryId
FROM (
SELECT amount, year, industryName, salaryId
, ROW_NUMBER() OVER(PARTITION BY year ORDER BY amount) AS rn
FROM salary
) a
WHERE rn = 1
Pre-MySQL 8 version
SELECT *
FROM salary s
INNER JOIN (
SELECT MIN(amount) AS minAmount, year
FROM salary
GROUP BY year
) m ON m.minAmount = s.amount AND m.year = s.year

I think you need a self-join :
SELECT s1.industryName, s2.min_salary, s2.salaryYear
FROM salary s1
JOIN
(
SELECT MIN(salary) as min_salary, salaryYear
FROM salary
GROUP BY salaryYear
) s2
ON s1.salary = s2.min_salary
AND s1.salaryYear = s2.salaryYear;
The Demo of this query with your sample data

Related

I keep getting an error when using an Aggregate function mySQL

Any thoughts on why the following doesn't work.
The Table is called Incomes, it has 3 cols called, name, dept and salary. I want to get the name and salary of personnel in the marketing dept whose salary is less than the average salary of all employees.
When I run the following I get ERROR 1111.
SELECT name, salary
FROM income
WHERE dept = "marketing"
HAVING salary < AVG(salary)
You must use a subquery in the WHERE clause that returns the average:
SELECT name, salary
FROM income
WHERE dept = 'marketing'
AND salary < (SELECT AVG(salary) FROM income WHERE dept = 'marketing')
If by all employees you mean the average salary of employees of all departments, then remove WHERE dept = 'marketing' from the subquery.
As an alternative to putting the subquery in the WHERE clause, we could use an inline view:
SELECT t.name
, t.salary
FROM ( SELECT AVG(d.salary) AS avg_salary
FROM income d
WHERE d.dept = 'marketing'
) a
JOIN income t
ON t.salary > a.avg_salary
AND t.dept = 'marketing'
With the inline view, we can also return the average salary, and we can calculate the difference, even a percentage difference, for multiple departments
Expanding on the query a bit, something like this:
SELECT a.dept
, t.name
, t.salary
, a.avg_salary
, ((t.salary - a.avg_salary) / a.avg_salary) * 100.0 AS pct_greater
FROM ( SELECT d.dept
, AVG(d.salary) AS avg_salary
FROM income d
GROUP
BY d.dept
) a
JOIN income t
AND t.dept = a.dept
ON t.salary > a.avg_salary
ORDER
BY a.dept
, t.salary DESC

my query doesn't return the max from value from the sum of working hours of the month

I want to find name of that persons who worked most in a month. but the query doesn't returning max value from sum of value
I'm new in mysql
SELECT
x.name,
sec_to_time(MAX(x.sum_time)) maximum
FROM (
SELECT
name,
SUM(TIME_TO_SEC(ending_time) - TIME_TO_SEC(starting_time)) sum_time
FROM working_hours wh, employees
WHERE wh.employees_id = employees.id
AND project_id IS NOT NULL
GROUP BY employees_id
) x
GROUP BY x.name;
this is my query. i want to show just name of that persons who worked most in a month. but it returns all persons who worked in a month
Try making these changes to your query:
change name to MAX(name)
qualify employees_id with wh.employees_id
SELECT
x.name,
sec_to_time(MAX(x.sum_time)) maximum
FROM (
SELECT
MAX(name) AS name,
SUM(TIME_TO_SEC(ending_time) - TIME_TO_SEC(starting_time)) sum_time
FROM working_hours wh, employees
WHERE wh.employees_id = employees.id
AND project_id IS NOT NULL
GROUP BY wh.employees_id
) x
group by x.name;
Simply use Order by LIMIT -
SELECT X1.name, X1.maximum
FROM (SELECT name, SUM(TIME_TO_SEC(ending_time) - TIME_TO_SEC(starting_time)) maximum
FROM working_hours wh, employees
WHERE wh.employees_id=employees.id
GROUP BY name) X1
JOIN (SELECT SUM(TIME_TO_SEC(ending_time) - TIME_TO_SEC(starting_time)) sum_time
FROM working_hours wh, employees
WHERE wh.employees_id=employees.id
AND project_id is not null
GROUP BY employees_id
ORDER BY sum_time DESC
LIMIT 1) X2 ON X2.sum_time = X1.maximum;

7th Highest salary in MYSQL

How to find the row with 7th highest salary from employee table in MySQL?
I have tried it this way but unable to get the exact query.
SELECT MAX(salary) FROM employee
WHERE salary NOT IN
(SELECT MAX(salary) FROM employee)
What a brief post!!! Try this though,
select *
from(
select distinct salary
from employee
order by salary desc limit 7
) t
order by salary
limit 1
maybe you can use this
SELECT * FROM employe ORDER BY salary DESC LIMIT 7
hope this will help you
I got the answer.
SELECT *
FROM one one1
WHERE ( 7 ) = ( SELECT COUNT( one2.salary )
FROM one one2
WHERE one2.salary >= one1.salary
)
SELECT *
FROM employees emp
WHERE 7 =
(SELECT COUNT(DISTINCT salary)
FROM employees
WHERE emp.salary<=salary );

Find 3rd Greatest Value with MySQL GROUP BY

I have a table with 3 columns:
Name department salary
How can I determine using one query to find 3rd highest salary in each department?
One way is to LIMIT a correlated subquery, but it's not especially efficient:
SELECT department, (
SELECT salary
FROM my_table t2
WHERE t2.department = t1.department
ORDER BY salary DESC
LIMIT 2, 1
)
FROM my_table t1
GROUP BY department
In addition to eggyal's excellent answer, here's a query that will give you the names, too, of those that have salary equal to the third (in each department):
SELECT
t.name, t.department, t.salary AS third_salary
FROM
( SELECT DISTINCT department
FROM tableX
) AS d
JOIN
tableX AS t
ON t.department = d.department
AND t.salary =
( SELECT tt.salary -- notice that this
FROM tableX AS tt -- subquery is
WHERE tt.department = d.department -- exactly the same as
ORDER BY tt.salary DESC -- the one in
LIMIT 1 OFFSET 2 -- #eggyal's answer
) ;
This RANK question is similar to this one:
MySQL, Get users rank
I you can thy this:
SELECT s.*,
(
SELECT COUNT(*)
FROM salaries si
WHERE si.salary >= s.salary AND si.department = s.department
) AS rank
FROM salaries s
WHERE s.rank = 3
Try this:
SELECT name, department, salary
FROM (SELECT name, department, salary, IF(#dept=(#dept:=department), #auto:=#auto+1, #auto:=1) indx
FROM employee e, (SELECT #dept:=0, #auto:=1) A
ORDER BY department, salary DESC ) AS A
WHERE indx = 3;

SQL Sum cumulative and non-cumulative in same query

Hi I was wondering if there is a way to get a cumulative and non-cumulative total in the same query. I have a table with following fields:
Department, SalesPerson, fin_month, activity, cost
What I would like is have two sums, one that would give a monthly total for salesperson, and another giving a year to date total. I am having a problem setting two different where criteria to get it to work.
Many Thanks
Would something like this help?
SELECT
*
FROM
(
SELECT
Department, SalesPerson
, SUM(fin_month) SalesPerson_Sum
FROM
[TABLE_NAME]
GROUP BY Department, SalesPerson
) a
INNER JOIN
(
SELECT
Department
, SUM(fin_month) AS Department_Sum
FROM
[TABLE_NAME]
GROuP BY
Department
) b
ON
a.Department = b.Department
This solution uses CTEs, recursion, and ranking to obtain cumulative totals for every fin_month per SalesPerson in every Department based on the corresponding monthly totals.
;WITH
monthlytotals AS (
SELECT
Department,
SalesPerson,
fin_month,
MonthlyTotal = SUM(cost),
rn = ROW_NUMBER() OVER (PARTITION BY Department, SalesPerson
ORDER BY fin_month)
FROM atable
GROUP BY Department, SalesPerson, fin_month
),
alltotals AS (
SELECT
Department,
SalesPerson,
fin_month,
MonthlyTotal,
CumulativeTotal = MonthlyTotal,
rn
FROM monthlytotals
WHERE rn = 1
UNION ALL
SELECT
m.Department,
m.SalesPerson,
m.fin_month,
m.MonthlyTotal,
CumulativeTotal = a.CumulativeTotals + m.MonthlyTotal,
m.rn
FROM monthlytotals m
INNER JOIN alltotals a
ON m.Department = a.Department
AND m.SalesPerson = a.SalesPerson
AND m.rn = a.rn + 1
)
SELECT
Department,
SalesPerson,
fin_month,
MonthlyTotal,
CumulativeTotal
FROM alltotals