sql query for a certain condition - mysql

I have a table like:
empId empSalary empDept
1 45000 IT
2 40000 IT
3 50000 SALES
4 60000 SALES
5 75000 IT
6 80000 IT
7 25000 OPS
8 30000 OPS
9 55000 MARKETING
10 60000 MARKETING
I have to write a query as:
select empId where empSalary > avg(empSalary) for each empDept
Kindly help.

Try this:
SELECT e.empId, e.empSalary, e.empDept
FROM employee e
INNER JOIN (SELECT e1.empDept, AVG(e1.empSalary) empSalary
FROM employee e1
GROUP BY e1.empDept
) a ON e.empDept = a.empDept AND e.empSalary > a.empSalary;
EDIT
SELECT e.empDept, COUNT(DISTINCT e.empid) noOfEmployees
FROM employee e
INNER JOIN (SELECT AVG(e1.empSalary) empSalary FROM employee e1) a ON e.empSalary > a.empSalary
GROUP BY e.empDept;

Could be something with a subquery, approximately as follows:
SELECT empID FROM TABLE t
WHERE empSalary > (SELECT AVG(empSalary) FROM TABLE WHERE empDept = t.empDept)
But can also be done with a JOIN that probably performs better:
SELECT empID FROM TABLE t
JOIN (SELECT empDept, AVG(empSalary) AS avgSalary FROM TABLE GROUP BY empDept) averages
ON t.empDept = averages.empDept
WHERE t.empSalary > averages.avgSalary
EDIT: the updated question calls for something slightly different, as per first comment below. Here's a count of how many employees are above the overall average salary, by department:
SELECT empDept, count(empID) FROM
(SELECT empID, empDept from TABLE
WHERE empSalary > (SELECT AVG(empSalary) FROM TABLE) aboveAverageEmployees
GROUP BY empDept

Related

How to join tables with aggregate functions in MYSQL query?

I have two tables from the database and I want to get the last status of each id. Tried adding the INNER JOIN claus but no avail. These are what my data looks like:
Table: employee
id name department
-------------------------
1 A X
2 B Y
3 C Z
Table: timelog
id time status count
-------------------------------
1 08:51 IN 1
3 09:00 OUT 2
2 09:00 IN 3
2 18:00 OUT 4
1 18:05 OUT 5
Currently, this is the query that I use but need to get the name of each employee.
SELECT
*
FROM timelog
WHERE timelog.count
IN (SELECT MAX(timelog.count)
FROM timelog
GROUP BY timelog.id)
ORDER BY clock.id;
Current output:
id time status
-------------------------------
1 18:05 OUT
2 18:00 OUT
3 09:00 OUT
This is the output I want to achieve:
id name time status
-------------------------------
1 A 18:05 OUT
2 B 18:00 OUT
3 C 09:00 OUT
Is it possible to add JOIN to the above query? If no, what would be the workaround? Any help would be greatly appreciated. TIA.
Use a correlated subquery to get the last record for each id in timelog:
SELECT e.*, tl.*
FROM employee e JOIN
timelog tl
ON e.id = tl.id
WHERE tl.count = (SELECT MAX(tl2.count)
FROM timelog tl2
WHERE tl2.id = tl.id
) ;
Note that your version of the query is not correct. The subquery returns the maximum count for each id. However, the outer query might match a different id to the count in the subquery. The correlation clause fixes this problem.
You can join the tables and use a correlated subquery for filtering:
select
e.id,
e.name,
t.time,
t.status
from employee e
inner join timelog t on t.id = e.id
where t.count = (
select max(count)
from timelog t1
where t1.id = t.id
)

Displaying supervisors who supervised 3 or more employees

Employee TABLE
ID Name Supervisor_ID
1 James NULL
2 Peter 1
3 Howard 1
4 Michele 2
5 Nicholas 2
6 Donald 2
7 Jackson 3
8 Anderson 3
9 Jeff 3
10 Will 3
I should get this at the end
ID Name Supervisor_Of_X_Employee
4 Peter 3
2 Howard 4
I tried doing
SELECT t1.employee_id
FROM employee t1
JOIN (SELECT DISTINCT supervisor_id FROM employee) t2
ON t1.employee_id = t2.supervisor_id;
Doesn't seem to produce what I want
Any ideas?
Thanks
You want to find the supervisor count so you group on the supervisor id like this
SELECT Supervisor_ID, count(*) as CNT
FROM employee
GROUP BY Supervisor_ID
add a HAVING COUNT(*) > 2 to get the ones that are 3 or more.
Oh... but you want the name too? then you have to join back to the table to get the name.
SELECT E.ID, E.Name, SUB.CNT
FROM (
SELECT Supervisor_ID, count(*) as CNT
FROM employee
GROUP BY Supervisor_ID
HAVING COUNT(*) > 2
) AS SUB
JOIN employee as E on E.ID = SUB.Supervisor_ID
SELECT Supervisor_id, COUNT(*) AS Supervisor_Of_X_Employee
FROM employee
GROUP BY Supervisor_id
if you need the name you'll have to do an inner join
SELECT employee_grouped.Supervisor_id, employee.Name, Supervisor_Of_X_Employee
FROM employee
INNER JOIN (
SELECT Supervisor_id, COUNT(*) AS Supervisor_Of_X_Employee
FROM employee
GROUP BY Supervisor_id
) employee_grouped ON employee.Id = employee_grouped.Supervisor_id
I would suggest using a self join approach with aggregation here:
SELECT
e1.Name,
COUNT(*) AS Supervisor_Of_X_Employee
FROM employee e1
INNER JOIN employee e2
ON e1.ID = e2.Supervisor_ID
GROUP BY
e1.Name
HAVING
COUNT(*) > 2;
Demo

Getting data form 2 tables and summing values of the result

I have 2 tables with information: ID, persona_id, total_amount
The persona ID can repeat dozen of times. So i get all the one persons id total_amount with query:
select d.id as debt_id, p.name as persona, sum(d.total_amount) as total_amount
from debt d
join persons p on d.persona_id = p.id group by p.name
I want to get data from each table in one query and do aritmethic propertys with the total_amount column and return it as 1 tabel.
TABLE 1
id persons_id total_amount
1 2 50
2 3 100
3 2 200
4 5 300
5 1 500
TABLE 2
id persons_id total_amount
1 2 25
2 1 100
3 5 50
4 3 100
5 4 300
As a result i want to get the 2 tables comined with arithmetic operation (-, +, / , * ) of Total amount columns.Basicaly a change to get the ending result total amount in form i want for different cases.
What worked for me based on JohnHC answear was :
select c.id, c.persona_id, c.total_amount - d.total_amount as new_total
from ( select c.id , c.persona_id, sum(c.total_amount) as total_amount from credit c
join persons p on c.persona_id = p.id
group by p.name) c
inner join ( select d.id, d.persona_id, sum(d.total_amount) as total_amount from debt d
join persons p on d.persona_id = p.id
group by p.name) d
on c.persona_id = d.persona_id
group by c.id, c.persona_id
If you want the total, try:
select id, person_id, sum(total_amount)
from
(
select id, person_id, total_amount
from table1
union all
select id, person_id, total_amount
from table2
)
group by id, person_id
If you want to do other things, try:
select t1.id, t1.person_id, t1.total_amount [+ - / *] t2.total_amount as new_total
from table1 t1
inner join table2 t2
on t1.id = t2.person_id
group by t1.id, t1.person_id

I want to have Sum of individual columns of two different table and show it in a single query result where customer id matches?

Create or replace view cnPointsDetailsvw
as select sum(cd.value), sum(cd1.points)
from customerdetails cd left join
customerdetails1 cd1 on cd.customerid = cd1.customerid;
The problem is that the above query is calculating sum multiple times for the column cd1.points
If table customerdetails1 has only 1 row, so why you use SUM() function?
Just use MAX().
I am confused of your table, so let me give a sample structurs and data.
table1
id points
-----------
1 10
2 20
3 40
table2
id points
-----------
1 10
1 2
1 4
2 20
3 40
3 5
And your query should be looks like this :
CREATE OR REPLACE VIEW view_name AS
SELECT t1.id,max(t1.points) as points1, sum(t2.points) as points2
FROM table1 t1
LEFT JOIN table2 t2 ON t1.id = t2.id
GROUP BY t1.id
Your view should be looks like this :
id points1 points2
---------------------
1 10 16
2 20 20
3 30 45
Do the calculation in subqueries, then join their results:
SELECT
CD.sum_value, CD1.sum_points
FROM
(SELECT sum(value) as sum_value FROM customerdetails) CD
INNER JOIN (SELECT sum(points) AS sum_points FROM customerdetails1) CD1
ON 1 = 1
Please note, that SUM() returns NULL if there were no matching rows, so the subqueries will return with exactly one record -> any ON condition will be fine which results to true.
If you want to group by customers, then do the grouping in the subqueries:
SELECT
CD.customerid, CD.sum_value, CD1.sum_points
FROM
(
SELECT customerid, sum(value) as sum_value
FROM customerdetails
GROUP BY customerid
) CD
LEFT JOIN
(
SELECT customerid, sum(points) AS sum_points
FROM customerdetails1
GROUP BY customerid
) CD1
ON CD.customerid = CD1.customerid
UPDATE
To create a view (and bypass the limitation of MySQL), you have to create 3 views: 2 for the 2 subresults, 1 to join their results:
CREATE VIEW customer_value AS
SELECT SUM(value) as sum_value FROM customerdetails;
CREATE VIEW customer_points AS
SELECT SUM(points) as sum_points FROM customerdetails1;
CREATE VIEW cnPointsDetailsvw AS
SELECT cv.sum_value, cp.sum_points
FROM customer_value cv
INNER JOIN customer_points cp
ON 1=1;

Update Duplicate column values based on Count in MySQl

I Have a Table like this
Employeeid Name CompanyID
1 Achal 1
2 Anil 1
3 Anil 1
4 Sachi 2
5 Anil 2
6 Sachi 1
7 Sachi 2
I want to update the names of the employee if multiple employees are there in a same company
My resultant table should be like this
Employeeid Name CompanyID
1 Achal 1
2 Anil(1) 1
3 Anil(2) 1
4 Sachi(1) 2
5 Anil 2
6 Sachi 1
7 Sachi(2) 2
My query is something like this
Update tblemplayee emp
join
(
select sname,count(*)
from tblemployee
group by sname,companyid
) innertable
on innertable.employeeid=emp.employeeid
set sname = concat(sname,'(', ,')') .
How can i change my query to get the result.
If you need to execute your query only once, you could use this query:
UPDATE
employees INNER JOIN (
SELECT e1.Employeeid, COUNT(e2.Employeeid) n
FROM
employees e1 INNER JOIN employees e2
ON e1.Name=e2.Name
AND e1.CompanyID=e2.CompanyID
AND e1.Employeeid>=e2.Employeeid
INNER JOIN (SELECT Name, CompanyID
FROM employees
GROUP BY Name, CompanyID
HAVING COUNT(*)>1) dup
ON e1.Name=dup.Name AND e1.CompanyID=dup.CompanyID
GROUP BY
e1.Employeeid, e1.Name) counts
ON employees.Employeeid = counts.Employeeid
SET
Name = CONCAT(Name, '(', counts.n, ')');
Please see fiddle here.