Not able to understand the query - mysql

I wanted to find two maximum salaries from every department in a table which had department no., salary, and various other columns. I got this answer; it surely works but I am not able to understand the logic.
select *
from emp a where 2 > (select count( distinct(sal))
from emp
where sal > a.sal and a.deptno=deptno)
order by deptno;

For each row in employee, the query within the WHERE clause counts how many rows have a higher salary in the same department. The WHERE clause itself then restricts the results to only those salaries which have 1 or 0 rows (2 >) in the same department with a greater salary - i.e. the highest two salaries.
So with this data:
EmployeeId Sal DeptNo No. of rows in the same department with higher salary
1 1 1 3 (employees 2, 3 and 4)
2 2 1 2 (employees 3 and 4)
3 3 1 1 (employee 4)
4 4 1 0
5 1 2 2 (employees 6 and 7)
6 2 2 1 (employee 7)
7 3 2 0
...the query will select employees 3, 4, 6 and 7, as they're the employees with fewer than 2 employees who have a higher salary than them.

The inner select returns the number of higher salaries within the same department for a given employee. Now if there are less than two higher salaries within the same department then the given employee must be the top earning or next-to-top earning person within the department.

Relocate the subquery to the SELECT clause without the 'top 2' restriction (will obviously get more rows back):
select a.*,
(
select count( distinct(sal))
from emp
where sal > a.sal and a.deptno=deptno
) as tally
from emp a
You can then restrict the resultset using a WHERE clause introducing a further level e.g.
select b.*
from (
select a.*,
(
select count( distinct(sal))
from emp
where sal > a.sal and a.deptno=deptno
) as tally
from emp a
) b
where b.tally < 2
order
by b.deptno, b.tally;
The above is more verbose but maybe easier to follow the logic.

Related

How to get common maximum element from three tables

I have three tables called table a, table b and table c
all the three tables have one common column.
How to get the common maximum value from the three tables?
here is my table info:
table a
id salary
101 10000
102 15000
103 18000
table b
id salary
110 14000
127 21000
118 15000
table c
id salary
191 15000
192 20000
193 8000
my required output is :
salary
15000
Use UNION ALL (or UNION) to get the salaries of all 3 tables with an extra column, like an id, which marks the source table and then in the HAVING clause of an aggregation query check if that salary belongs to all tables.
Finally use ORDER BY with LIMIT 1 to get the max common salary:
SELECT salary
FROM (
SELECT 1 id, salary FROM tableA UNION ALL
SELECT 2 id, salary FROM tableB UNION ALL
SELECT 3 id, salary FROM tableC
) t
GROUP BY salary
HAVING COUNT(DISTINCT id) = 3 -- get only the common salaries
ORDER BY salary DESC LIMIT 1;
You can use inner joins between the tables to make sure you're only considering values that occur in all three tables.
Then use MAX() to get the greatest of such values.
SELECT MAX(salary) AS salary
FROM tableA JOIN tableB USING (salary) JOIN tableC USING (salary)

Query BETWEEN TWO TABLES OUTPUT (MYSQL)

two table EMPLOYEE and Department
EMPLOYEE's fields are ID,Name, Salary ,DEPT_ID(foreign key to department table)
DEPARTMENT'S fields are id,NAME,LOCATION
VALUES OF EMPLOYEE TABLE WILL Be
Values OF DEPARTMENT TABLE WILL BE
Output from these table should be
DEPARTMENT_Name should be alpabetically within their count If are there same Count DEPARTMENT_Name should appear in alpabetically and count will be desc order
EMPLOYEE TABLE Values
id name salary dept_id
1 Candice 4685 1
2 Julia 2559 2
3 Bob 4405 4
4 Scarlet 2305 1
5 Ileana 1151 4
Department TABLE Values
id name location
1 Executive Sydney
2 Production Sydney
3 Resources Cape Town
4 Technical Texas
5 Management Paris
OUTPUT DATA SHOULD BE
DEPARTMENT_Name Count_OF_EMPLOYEE_SAME_DEPARTMENT
Executive 2,
Technical 2,
PRODUCTION 1,
MANAGEMENT 0,
RESOURCES 0
For what you want to show all departments even if there are no employees is a LEFT JOIN. So, start with the department table (alias "d" in the query) and LEFT JOIN to the employee table (alias "e"). using shorter alias names that make sense with context makes readability easier.
Now, you have the common "count()" which just returns a count for however many records are encountered, even if multiple in the secondary (employee) table based on common ID. In addition to count(), I also did a sum of the employee salary just for purposes that you can get multiple aggregate values in the same query.. Use it or don't, just wanted to present as an option for you.
Now the order. You want that based on the highest count first, so the COUNT(*) DESC (descending order) is the first sorting. Secondary is the department name to keep alphabetized if within the same count.
select
d.`name` Department_Name,
d.Location,
count(*) NumberOfEmployees,
sum( coalesce( e.salary, 0 )) as DeptTotalSalary
from
Department d
left join employee e
on d.dept_id = e.id
group by
d.`name`
order by
count(*) desc,
d.`name`

Display column values and their count on SQL

I just want to ask you please this question on SQL.
Let's consider this EMPLOYEE table :
Employee Department
A 10
A 10
A 11
A 12
B 13
B 13
What I want to display is for each employee, all distinct departments (without duplicates) AND the total number of those distinct departments. So, something like this :
Employee Department total_dept
A 10 3
A 11 3
A 12 3
B 13 1
If possible, I would even prefer something like these :
Employee Department total_dept
A 10 3
A 11 null
A 12 null
B 13 1
I have a very big table (with many columns and many data) so I thought this can be an "optimisation", no ? I mean, there is no need to store the total_dept in all rows. Just put it once it's sufficient. No problem if after this I left the column empty. But I don't know if it's possible to do such thing in SQL.
So, how can I fix this please ? I tried but it seems impossible to combine count(column) with the same column...
Thank you in advance
This might be what you are looking for
SELECT
emp,
dept,
(select count(distinct dept) from TB as tbi where tb.emp = tbi.emp ) x
FROM TB
group by emp, dept;
MySQL 8.0 supports windowed COUNT:
SELECT *,COUNT(*) OVER (PARTITION BY Employee) AS total_dept
FROM (SELECT DISTINCT * FROM Employees) e
db<>fiddle demo
You could even have second resulset(I recommend to leave presentation matter to apllication layer):
SELECT *, CASE WHEN ROW_NUMBER() OVER(PARTITION BY Employee ORDER BY Department) = 1
THEN COUNT(*) OVER (PARTITION BY Employee) END AS total_dept
FROM (SELECT DISTINCT * FROM Employees) e
ORDER BY Employee, Department;
db<>fiddle demo
For the 2nd version:
SELECT
DISTINCT e.Employee, e.Department,
CASE
WHEN e.Department =
(SELECT MIN(Department) FROM Employees WHERE Employees.Employee = e.Employee)
THEN
(SELECT COUNT(DISTINCT Department) FROM Employees WHERE Employees.Employee = e.Employee)
END AS total_dept
FROM Employees e
ORDER BY e.Employee, e.Department;
See the demo

My sql Group By case for getting highest paid employee in specific year

there is two table
1 Employee
2 salary
Employee : eId, ename, salaryId
Salary : salaryId, eId, salary, date
salary table contains monthly record of employee salary,
like:
eId date salary
1 2015-jan-01 10000
1 2015-feb-01 10000
1 2015-mar-01 10000
1 2014-jan-01 10000
1 2014-feb-01 10000
1 2014-mar-01 10000
2 2015-jan-01 10000
2 2015-feb-01 10000
2 2015-mar-01 10000
2 2014-jan-01 10000
2 2014-feb-01 10000
2 2014-mar-01 20000
so the query is to give me highest paid employee in specific year for ex: 2014
so here using group by with date and sum of salary output is :
empid - empname - sum(salary)
2 - xyz - 40000
Try it with something like this ... i just took a glance to point you toward right direction, this query might need some fixing
Select TOP 1 emp.eid, emp.ename, sal.salary
from Employee emp
join Salary sal on emp.salaryID = sal.salaryID
where DATEPART(yy,sal.date) = 2014
order by sal.salary desc
Good luck
Something like this could work
with salaries as (
select to_char(date,'yyyy') y, eld, sum(salary) s_sal
from salary
group by to_char(date,'yyyy'), eld)
select eld
from salaries s
where s_sal = (select max(s_sal) from salaries where y=s.y)
and s.y='2014';
But you didn't specify DB, so there is Oracle syntax.
And I didn't join with Employee table, but believe it isn't hard to add it.
If the requirement is to get the list of highest paid employee in each year then this can be achieved by a "Ranking" logic.
Something like this:
SELECT
Year(SalaryMonthDate) AS [Payroll Year],
EID,
Sum(Amout) AS [Annual Salary],
RANK() OVER(PARTITION BY Year(SalaryMonthDate) ORDER BY Sum(Amout) DESC) [Rank]
FROM tblSalary
GROUP BY Year(SalaryMonthDate), EID
Hope this helps.
MySQL Code,
SELECT Top 1 E.ename EmployeeName,
MAX(salary) AS EmployeeSalary
FROM Employee E
INNER JOIN Salary S
ON E.salaryID = S.salaryID
WHERE YEAR(S.Date) = 2014
GROUP BY
E.eId,
E.ename
#highest paid emp in specific year
SELECT e.empId,e.empName,SUM(s.salary),s.salDate
FROM emp e INNER JOIN salary s ON e.empId = s.empId
WHERE YEAR(s.salDate)=2009 GROUP BY s.empId ORDER BY SUM(s.salary) DESC LIMIT 1;

How to combine the outcome of query?

I have a table about metro card of station enter and record record(cid, enter_sid, exit_sid)
I want to get the total number of enter and out each station.
For example,
cid enter_sid exit_sid
1 1 2
1 1 2
1 2 3
2 2 1
I want to get
sid count(*)
1 3
2 4
3 1
I don't know how to combine select cid, count(*) from record group by enter_sid and select cid, count(*) from record group by exit_sid
cid means id of card.
For the first row of my expected outcome, 1 is for the id of station, 3 is for sid 1 existing 2 times in enter_sid and 1 time in exit_sid.
the trick to this is your enter and exit sid are the first column so you have to union those two together to get the correct combination... from there its a simple sum of the count.
SELECT sid, cid, SUM(counting) FROM
(
SELECT cid, enter_sid as sid, COUNT(*) as counting FROM record GROUP BY enter_sid
UNION ALL
SELECT cid, exit_sid as sid, COUNT(*) as counting FROM record GROUP BY exit_sid
)t
GROUP BY sid
Working Fiddle