I keep getting an error when using an Aggregate function mySQL - 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

Related

SQL Group by returning wrong results

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

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;

Invalid use of group by while showing username with heighest salary in group

I use MySQL
I wanted to show some records like Total Salary per designation , avg salary etc. All are working except : I want to show person name with heighest salary in group. When I use the query as below , I give error : Invalid use of group function . I ran it many times using different tweaks , ordering of query , still giving error. What may be the issue here ?
SELECT designation , SUM(salary) as salary_as_per_designation ,
count(*) as num_employees ,
avg(salary) as avg_salary ,
MIN(salary) as min_salary_of_emp_per_designation,
MAX(salary) as max_salary_of_emp_per_designation ,
(SELECT name FROM articles where salary = max(salary) GROUP BY designation LIMIT 1) as emp_name_min_sal
FROM articles GROUP BY designation;
The weired thing is when i use on 2nd last line above like .... where salary = 10000... 100 as Some random value query works but gives wrong result , I mean wrong name for the user with heighest salary in group.
My table structure is as follows :
CREATE TABLE IF NOT EXISTS `articles` (
`id` int(12) NOT NULL,
`name` varchar(256) NOT NULL,
`salary` double NOT NULL,
`designation` enum('tech_support','developer','tester','designer') NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;
Thanks.
SELECT ilv.*,
(SELECT GROUP_CONCAT(name)
FROM articles
where salary = ilv.max_salary_of_emp_per_designation
) as emp_name_min_sal
FROM
(
SELECT designation , SUM(salary) as salary_as_per_designation ,
count(*) as num_employees ,
avg(salary) as avg_salary ,
MIN(salary) as min_salary_of_emp_per_designation,
MAX(salary) as max_salary_of_emp_per_designation
FROM articles
GROUP BY designation
) AS ilv
Does this work? Note sub-select conditions, you're looking for salaries within the designation grouping?
SELECT designation,
SUM(salary) as salary_as_per_designation,
count(*) as num_employees,
avg(salary) as avg_salary,
MIN(salary) as min_salary_of_emp_per_designation,
MAX(salary) as max_salary_of_emp_per_designation,
(SELECT max(name)
FROM articles
where designation = a1.designation
and salary = (select max(salary) from articles
where designation = a1.designation)) as emp_name_min_sal
FROM articles a1
GROUP BY designation;
Use this query instead,
SELECT MAX(salary) into #max_sal FROM articles;
SELECT designation , SUM(salary) as salary_as_per_designation ,
count(*) as num_employees ,
avg(salary) as avg_salary ,
MIN(salary) as min_salary_of_emp_per_designation,
MAX(salary) as max_salary_of_emp_per_designation ,
(SELECT name FROM articles where salary = #max_sal GROUP BY designation LIMIT 1) as emp_name_min_sal
FROM articles GROUP BY designation;
Hope this will work, thank you.

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