Query help in SQL - mysql

I have the below table, with empid, deptid, and Name. I need to get the results as
empid,deptid,name and count of employees in each department.
CREATE TABLE emp(empid INTEGER PRIMARY KEY, deptid INTEGER, NAME TEXT);
/* Create few records in this table */
INSERT INTO emp VALUES
(1,100,'Tom'),
(2,200,'Lucy'),
(3,300,'Frank'),
(4,100,'Jane'),
(5,400,'Robert');
I need to get the results as empid,deptid,name, and count of employees in each department as below.
I am able to achieve results using the below queries.
SELECT a.empid, a.deptid, a.Name, result.emp_dept_count FROM emp a,
( SELECT b.deptid, COUNT(b.deptid) AS emp_dept_count FROM emp b
GROUP BY b.deptid ) result
WHERE a.deptid = result.deptid;
/* using common table expression */
WITH emp_dept_count_cte(deptid,emp_dept_count) AS ( SELECT b.deptid, COUNT(b.deptid) AS emp_dept_count FROM emp b
GROUP BY b.deptid )
SELECT a.empid, a.deptid, a.Name, result.emp_dept_count
FROM emp a, (SELECT deptid, emp_dept_count FROM emp_dept_count_cte) result
WHERE a.deptid = result.deptid;
/* using common table expression */
WITH emp_dept_count_cte (deptid,emp_dept_count) AS ( SELECT b.deptid, COUNT(b.deptid) AS emp_dept_count FROM emp b
GROUP BY b.deptid )
SELECT a.empid, a.deptid, a.Name, emp_dept_count_cte.emp_dept_count
FROM emp a
INNER JOIN emp_dept_count_cte
ON a.deptid = emp_dept_count_cte.deptid;
/* using common table expression */
WITH emp_dept_count_cte (deptid,emp_dept_count) AS ( SELECT b.deptid, COUNT(b.deptid) AS emp_dept_count FROM emp b
GROUP BY b.deptid )
SELECT a.empid, a.deptid, a.Name, emp_dept_count_cte.emp_dept_count
FROM emp a
LEFT JOIN emp_dept_count_cte
ON a.deptid = emp_dept_count_cte.deptid;
Is it possible to do this in alternate ways?

No need for CTE. Just do
SELECT *, COUNT(1) OVER (PARTITION BY deptid) AS emp_dept_count FROM emp

You are describing a window count:
select e.*,
count(*) over(partition by deptid) as emp_dept_count
from emp e
In pre-8.0 MySQL versions, where window functions are not supported, you can use a correlated subquery:
select e.*,
(select count(*) from emp e1 where e1.deptid = e.deptid) as emp_dept_count
from emp e
Or you can join an aggregate query:
select e.*, d.emp_dept_count
from emp e
inner join (select deptid, count(*) as emp_dept_count from emp group by deptid) d on d.deptid = e.deptid

Related

How to solve errors in MySql subquery

I'm learning Mysql, a newbie.
First I wrote:
Select name, count(*)
From Emp
Group By name;
and the code was successful.
After that, I added to the code it became:
Select *
From Emp
Where (Select name, count(*)
From Emp
Group By name) > 1;
and I get an error message too many values.
How to fix that?
To get the name which have the count >1 use having count clause.
Try:
Select name,
count(*)
From Emp
Group By name
having count(name) > 1;
Learn more on: https://www.mysqltutorial.org/mysql-count/
select e.*
from Emp e
INNER JOIN (Select name,
count(*)
From Emp
Group By name
having count(name) > 1
) as e2 on e2.name=e.name
To get all the information of the employees that have the same name, you can do folowing
Select e1.*
From Emp e1 INNER JOIN (Select name
From Emp
Group By name
having count(name) > 1) e2 ON e2.name = e1,name

Join data from two tables with distinct to select unique job titles

I have two tables: employees and offices.
I want to create a view with all the columns from 'employees', but only two columns of 'offices'.
Also, I want to select only employees who have unique job titles. I'm trying to do it with the following code, but it returns the following error:
#1248 - Every derived table must have its own alias.
I'm using the following query:
SELECT employees.*, offices.officeCode, offices.phone
FROM (
SELECT DISTINCT employees.jobTitle
)
JOIN offices ON employees.officeCode = offices.officeCode
offices table:
employees table:
Desired result:
employeeNumber|jobTitle|firstName|officeCode|city|state|country
including only the first 6 employees from the sample image (as 'Sales Rep' is a repeated jobTitle, the employees with it wouldn't be included).
Current query has a number of issues:
As error indicates, derived table or subquery does not have an alias.
Incomplete SELECT query in derived table without FROM clause: (SELECT distinct emplyees.jobtitle)
Retrieving columns from a table not referenced in data sources of query (i.e., employees)
Therefore, consider joining the two tables with a count check on unique job title:
SELECT e.*, o.officeCode, o.phone
FROM employees e
INNER JOIN offices o
ON e.officeCode = o.officeCode
WHERE e.jobTitle IN
(SELECT sub.jobTitle
FROM employees sub
GROUP BY sub.jobTitle
HAVING COUNT(*) = 1)
With this query:
SELECT e.*
FROM employees e
WHERE NOT EXISTS (SELECT 1 FROM employees WHERE employeeNumber <> e.employeeNumber AND jobTitle = e.jobTitle)
you get all the employees with jobTitle that does not have any other employee.
So join it to offices:
SELECT e.employeeNumber, e.jobTitle, e.firstName, o.*
FROM (
SELECT e.*
FROM employees e
WHERE NOT EXISTS (SELECT 1 FROM employees WHERE employeeNumber <> e.employeeNumber AND jobTitle = e.jobTitle)
) e INNER JOIN offices o
ON e.officeCode = o.officeCode
Just use window functions:
SELECT e.*, o.officeCode, o.phone
FROM (SELECT e.*, COUNT(*) OVER (PARTITION BY jobTitle) as job_cnt
FROM employees e
) e JOIN
offices o
ON e.officeCode = o.officeCode
WHERE job_cnt = 1;

Find those companies whose employees earn a higher salary, on average, than the average salary at “Wipro”

I have tried one sql but not working
select cname,avg(salary)
from Company as co,Works as wo
where co.cid=wo.cid and wo.salary > (select avg(salary)
from Company as c,Works as w
where c.cid=w.cid and c.cname='Wipro');
Employee (EID, EName, City)
Works (EID, CID, Salary)
Company (CID, CName, City)
create table Employee(eid int primary key,ename varchar(6),city varchar(6))
create table Works(eid int,cid int primary key,salary int)
create table Company(cid int,cname varchar(6),city varchar(6))
alter table Works add foreign key(eid) references Employee(eid)
alter table Works add foreign key(cid) references Company(cid)
Learn to use proper, explicit, standard JOIN syntax.
That said, you are close. You just need a HAVING clause:
select c.cname, avg(w.salary)
from Company c join
Works w
on c.cid = w.cid
group by c.cname
having avg(w.salary) > (select avg(w2.salary)
from Company c2 join
Works w2
on c2.cid = w2.cid
where c2.cname = 'Wipro'
);
Notes:
Never use commas in the FROM clause.
You should have a GROUP BY when you are using AVG().
Conditions on summarized values should be in the HAVING clause.
SELECT t1.CName,
t2.AvgSalary
FROM Company t1
INNER JOIN (SELECT AVG(Salary) AS AvgSalary,
CID
FROM Works
GROUP BY CID) t2 ON t1.CID = t2.CID
WHERE t2.AvgSalary > (SELECT AVG(Salary)
FROM blog.Works t1a
INNER JOIN blog.Company t2a ON t1a.cid = t2a.cid
WHERE t2a.cname = 'Wipro');
When there's a GROUP BY then you can use the aggregate functions like a SUM in the HAVING clause.
SELECT
co.cname AS company_name,
AVG(wo.salary) AS avg_salary
FROM Company AS co
JOIN Works AS wo ON wo.cid = co.cid
GROUP BY co.cname
HAVING AVG(wo.salary) > (
SELECT AVG(salary)
FROM Company AS c
JOIN Works AS w ON w.cid = c.cid
WHERE c.cname = 'Wipro'
);
You can try it here

Fetch only the department that has the highest number of employees

I have 2 tables in my database.
Table 1. employee
id
name
department_id
Table 2. department
id
name
What will be the query to fetch all employees with their department?
So I have written this query
SELECT employee.name
, department.name
FROM employee
JOIN department
ON employee.department_id = department.id
And this seems to be correct but I am not able to write a query if I want to fetch only the department that has the highest number of employees. How can I achieve this?
To guarantee just one department...
SELECT
*
FROM
department
WHERE
id = (SELECT department_id
FROM employee
GROUP BY department_id
ORDER BY COUNT(*) DESC
LIMIT 1
)
Note, if two departments are tied with joint maximum employees, this will still only select One of them (arbitrarily chosen, potentially different each time).
To handle ties, you could do the following...
SELECT *
FROM department
WHERE id IN (SELECT department_id
FROM employee
GROUP BY department_id
HAVING COUNT(*) = (SELECT COUNT(*)
FROM employee
GROUP BY department_id
ORDER BY COUNT(*) DESC
LIMIT 1
)
)
This is a real pain to handle in MySQL. Here is one option:
SELECT d1.id, d1.name
FROM department d1
INNER JOIN employee e1
ON d1.id = e1.department_id
GROUP BY d1.id, d1.name
HAVING COUNT(*) = (SELECT COUNT(*) FROM department d2 INNER JOIN employee e2
ON d2.id = e2.department_id
GROUP BY d2.id ORDER BY COUNT(*) DESC LIMIT 1);
Note that if you were using a database with analytic function support, such as SQL Server, then the problem gets much easier:
SELECT id, name
FROM
(
SELECT d.id, d.name, DENSE_RANK() OVER (ORDER BY COUNT(*) DESC) dr
FROM department d
INNER JOIN employee e
ON d.id = e.department_id
GROUP BY d.id, d.name
) t
WHERE t.dr = 1;
This question can be solved in multiple ways:
Using sub query
SELECT name FROM department
WHERE id IN
(SELECT department_id FROM employee HAVING COUNT(department_id)
IN
(SELECT MAX(COUNT(department_id)) FROM employee) GROUP BY department_id)
Using Join
SELECT name FROM employee e
INNER JOIN
department d ON e.department_id = d.id
HAVING COUNT(e.department_id)
IN
(SELECT MAX(COUNT(department_id)) from employee) group by department_id)
first check the column related two types have same name, same data type and the use subquery
SELECT name
FROM department
WHERE id IN (
SELECT department_id
FROM employees
HAVING COUNT(department_id) IN (
SELECT MAX(COUNT(dept_id))
FROM employees
)
GROUP BY department_id
)
Your query should work for the first question.
for the second, You can use this. The sub query would give you the dept Id for the most employees, which the outer query would give additional details for.
select * from department where department_id in
(select limit 1 Employee.department_id from Employee group by department_id
order by count(Employee.name) desc)

select department(s) with maximum number of employees

I have two tables EMP(id,name,DEPT_id) and DEPT(id ,name). I need to find the department(s) in which the maximum number of employees work. Please help.
This will give the department name of the department which is having maximum number of employees.
Select DEPT_NAME from department where DEPT_ID = (select DEPT_ID from (Select DEPT_ID, count(DEPT_ID) from Employee group by DEPT_ID order by count(DEPT_ID) desc) where rownum = 1);
Just a little more verbose than the other two solutions, but it will get the job done...feel free to tweak to your convenience.
select countbydept.*
from
(
-- from EMP table, let's count number of records per dept
-- and then sort it by count (highest to lowest)
-- and take just the first value. We just care about the highest
-- count
select dept_id, count(*) as counter
from emp
group by dept_id
order by counter desc
limit 1
) as maxcount
inner join
(
-- let's repeat the exercise, but this time let's join
-- EMP and DEPT tables to get a full list of dept and
-- employe count
select
dept.id,
dept.`name`,
count(*) as numberofemployees
from dept
inner join emp on emp.dept_id = dept.id
group by dept.id, dept.`name`
) countbydept
-- combine the two queries's results by matching the employee count
on countbydept.numberofemployees = maxcount.counter
Example: http://sqlfiddle.com/#!9/7d6a2d/1
Try this query.
SELECT a.name,Max(a.NumEmp) AS maxEmpCount FROM ( SELECT d.name,COUNT(*) AS NumEmp FROM EMP e INNER JOIN DEPT d ON e.DEPT_id = d.id GROUP BY e.DEPT_id ) AS a GROUP BY a.name
you can solve this using with statement like this:
with deps as
(select dep.department_name as dep_name, count(emp.employee_id) as cnt
from departments dep
inner join employees emp
on emp.department_id = dep.department_id
group by dep.department_name)
select deps.dep_name,cnt from deps
where cnt=(select max(cnt) from deps)
OR
select dep.department_name as dep_name, count(emp.employee_id) as cnt
from departments dep
inner join employees emp
on emp.department_id = dep.department_id
group by dep.department_name
having count(emp.employee_id) >= all (select count(emp.employee_id) as cnt
from departments dep
inner join employees emp
on emp.department_id =
dep.department_id
group by dep.department_name)
OR
with s1 as
(select dep.department_name as dep_name,
count(emp.employee_id) over(partition by dep.department_name) as cnt
from departments dep
inner join employees emp
on emp.department_id = dep.department_id
order by cnt desc),
s2 as
(select s1.dep_name,
s1.cnt,
row_number() over(order by cnt desc) as row_num
from s1)
select dep_name from s2 where row_num = 1
these solutions are proper for databases like Oracle that we do not have top(1) or limit 1
select Top 1 d.DNAME,count(e.ename) as counts from emp e,dept d where d.DEPTNO=e.DEPTNO
group by d.DNAME
order by counts desc
Or
select d.DNAME,count(e.ename) as counts from emp e,dept d where d.DEPTNO=e.DEPTNO
group by d.DNAME
having count(e.ename) = (select max(micount) from (select count(deptno) micount from emp group by DEPTNO) a)
You can try this query.
Select Id, Name from Dept
Where Id = (Select Top(1) DeptId from Emp
Group By DeptId
order by Count(DeptId) desc)
you can create view to find it.
CREATE VIEW TEMP AS SELECT COUNT(EMP.id) AS A, DEPT.name AS B
FROM EMP JOIN DEPT ON EMP.DEPT_id=DEPT.id GROUP BY DEPT.id;
SELECT MAX(A) FROM TEMP;
Now, EMP(id,name,DEPT_id) and DEPT(id ,name) these two tables are given. Now, I insert some entries in the table in such a manner that:
SELECT COUNT(*) AS NO_OF_EMPLOYEES,
DEPARTMENT.DEPT_NAME
FROM EMP, DEPARTMENT
WHERE EMP.DEPT_ID=DEPARTMENT.DEPT_ID
GROUP BY EMP.DEPT_ID
ORDER BY NO_OF_EMPLOYEES;
This query generates the following:
NO_OF_EMPLOYEES DEPT_NAME
3 Research
3 Finance
4 Sales
4 Product
Now, the query which gives the correct result:
SELECT COUNT(*) AS MAX_NO_OF_EMPLOYEES,
DEPARTMENT.DEPT_NAME
FROM EMP, DEPARTMENT
WHERE EMP.DEPT_ID=DEPARTMENT.DEPT_ID
GROUP BY EMP.DEPT_ID
HAVING MAX_NO_OF_EMPLOYEES=(
SELECT COUNT(*) AS NO_OF_EMPLOYEES
FROM EMP
GROUP BY DEPT_ID
ORDER BY NO_OF_EMPLOYEES DESC
LIMIT 1
);
It will generate:
MAX_NO_OF_EMPLOYEES DEPT_NAME
4 Sales
4 Product
This question can be solved in multiple ways
Using sub query
SELECT name FROM dept WHERE id IN (SELECT dept_id FROM emp HAVING COUNT(dept_id) IN (SELECT MAX(COUNT(dept_id)) FROM emp) GROUP BY dept_id)
Using Join
SELECT name FROM emp e INNER JOIN dept d ON e. dept_id = d. id HAVING COUNT(e.dept_id) IN (SELECT MAX(COUNT(dept_id)) from emp) group by dept_id)
If you have only emp table then below query will hep you get a results -
select a.* from (select deptno, dense_rank() over(order by count(*) desc ) as rank from dbo.emp group by deptno) a where a.rank =1
select deptno,count(*)from emp group by
deptno having count(*)=(select max(count(*))from emp group by deptno);
SELECT department_id, count(employee_id) as 'No_of_Emp'
FROM employees
GROUP BY department_id
ORDER BY No_of_Emp DESC