This question already has answers here:
What is the difference between count(0), count(1).. and count(*) in mySQL/SQL?
(9 answers)
Closed 3 years ago.
I use oracle 11g. I want maximum and minimum salary, and count of employees for each department, so I do this :
select d.department_id, d.department_name, max(salary), min(salary), count(*)
from employees e ,
departments d
where e.department_id = d.department_id
group by d.department_id, d.department_name;
and it works :
DEPARTMENT_ID DEPARTMENT_NAME MAX(SALARY) MIN(SALARY) COUNT(*)
------------- ------------------------------ ----------- ----------- ----------
100 Finance 12008 6900 6
50 Shipping 8200 2100 45
70 Public Relations 10000 10000 1
30 Purchasing 11000 2500 6
90 Executive 24000 17000 3
10 Administration 4400 4400 1
110 Accounting 12008 8300 2
40 Human Resources 6500 6500 1
20 Marketing 13000 6000 2
60 IT 9000 4200 5
80 Sales 14000 6100 34
11 rows selected.
So what does count(*) mean? Count departments or what ?
count(*) returns the rows that match the where statement.
In your case its where e.department_id=d.department_id.
Because you applied a group by your count(*) will return the count of rows for each group (d.department_id).
This means you will get the count of employees (e.department_id) for each department (d.department_id).
Related
Following are the results of my sql queries:
SELECT DISTINCT(department_id)
from employees
ORDER BY department_id;
Result:
DEPARTMENT_ID
10
20
30
40
50
60
70
80
90
100
110
Then:
SELECT department_id
FROM departments
ORDER BY department_id;
DEPARTMENT_ID
10
20
30
40
50
60
70
80
90
100
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
When I execute the Following Query, I get the result:
SELECT department_id
from departments
where department_id IN (select distinct(department_id) from employees)
ORDER BY department_id;
DEPARTMENT_ID
10
20
30
40
50
60
70
80
90
100
110
However, the following query returns "NO Rows Selected" when I execute the following query:
SELECT department_id
from departments
WHERE department_id NOT IN (select distinct(department_id) from employees)
ORDER BY department_id;
What I was expected was the Id of departments that are not present in Employees table.
I feel its a beginner's mistake however i am not able to resolve this issue. Any help would be largely appreciated.
This is because at least one department_id in employees isNULL. When any value in theNOT INlist isNULL`, no rows are returned at all.
To fix this, I simply recommend always using NOT EXISTS with a subquery:
SELECT d.department_id
FROM departments d
WHERE NOT EXISTS (SELECT 1 FROM employees e WHERE d.department_id = e.department_id)
ORDER BY d.department_id;
(Or by using a LEFT JOIN/WHERE.)
You could fix this using a WHERE clause in the subquery. I think it is better to use a construct that does what you intend.
I want to combine the "COUNT(DEPARTMENT_ID)" column based on if the "LOCATION_ID" are the same as the corresponding "DEPARTMENT_ID" from another select statement. I have this select statement that gives me how many times "DEPARTMENT_ID" comes up.
select DEPARTMENT_ID, COUNT(DEPARTMENT_ID) FROM EMPLOYEES GROUP BY DEPARTMENT_ID;
Output:
DEPARTMENT_ID COUNT(DEPARTMENT_ID)
------------- --------------------
100 6
30 6
0
90 3
20 2
70 1
110 2
50 45
80 34
40 1
60 5
DEPARTMENT_ID COUNT(DEPARTMENT_ID)
------------- --------------------
10 1
12 rows selected.
And I have this other select that tells me what "DEPARTMENT_ID" corresponding "LOCATION_ID" is but I am not sure how to combine the "COUNT(DEPARTMENT_ID)" based on if the "LOCATION_ID" are the same.
select DEPARTMENT_ID, LOCATION_ID from DEPARTMENTS;
Output:
DEPARTMENT_ID LOCATION_ID
------------- -----------
10 1700
20 1800
30 1700
40 2400
50 1500
60 1400
70 2700
80 2500
90 1700
100 1700
110 1700
DEPARTMENT_ID LOCATION_ID
------------- -----------
120 1700
130 1700
140 1700
150 1700
160 1700
170 1700
180 1700
190 1700
200 1700
210 1700
220 1700
DEPARTMENT_ID LOCATION_ID
------------- -----------
230 1700
240 1700
250 1700
260 1700
270 1700
27 rows selected.
Any Ideas?
If your objective is to simply count the number of departments based on its location then the below query would be suffice.
select LOCATION_ID, count(DEPARTMENT_ID) from DEPARTMENTS group by LOCATION_ID
If you need count of employees based on the location the you need to use inner join and group by location id.
select t2.LOCATION_ID, COUNT(t1.DEPARTMENT_ID)
FROM EMPLOYEES t1 INNER JOIN (select DEPARTMENT_ID, LOCATION_ID from DEPARTMENTS) t2
on t1.DEPARTMENT_ID = t2.DEPARTMENT_ID GROUP BY t2.LOCATION_ID ;
Updated code:
You can use Inner Join, the INNER JOIN keyword selects records that have matching values in both tables. You can use following query.
select t1.DEPARTMENT_ID, COUNT(t1.DEPARTMENT_ID) ,t2.LOCATION_ID FROM EMPLOYEES t1 INNER JOIN (select DEPARTMENT_ID, LOCATION_ID from DEPARTMENTS) t2
on t1.DEPARTMENT_ID = t2.DEPARTMENT_ID GROUP BY t1.DEPARTMENT_ID,t2.LOCATION_ID ;
I have a little problem. Here's a code:
select * from
(select department_id, manager_id,last_name, salary, row_number() over
(partition by department_id,manager_id order by salary asc) p_number
from employees )
where p_number <=3;
This query shows 3 the least salaries in every department for every manager in department
ex: Dep no.30 has 2 managers (100 and 114), manager no.100 has 1 employee beneath him, manager no.114 - 3 employees.
part of result:
20 100 Hartstein 13000 1
20 201 Fay 6000 1
30 100 Raphaely 11000 1
30 114 Colmenares 2500 1
30 114 Himuro 2600 2
30 114 Tobias 2800 3
Now, i want to delete all rows, where there is only 1 employee beneath manager. In this example there should be, Harstein, Fay, Raphaely. Colmenares also has number 1, but there is more employees under manager 114.
Any ideas?
PS Having Count is out, because there is no group by, and modifying
where p_number <=3;
into
where p_number <=3 and p_number >1;
is also out, because it will delete all my employees with no.1 and i want to 'safe' few as they have more 'colleagues' :)
Thanks!
This will give the result and only require a single table scan:
SELECT *
FROM (
SELECT department_id,
manager_id,
last_name,
salary,
ROW_NUMBER()
OVER ( PARTITION BY department_id, manager_id
ORDER BY salary ASC ) AS p_number,
COUNT(*)
OVER ( PARTITION BY department_id, manager_id ) AS p_count
FROM employees
ORDER BY department_id, manager_id, salary
)
WHERE p_count >= 2
AND p_number <= 3;
Output:
DEPARTMENT_ID MANAGER_ID LAST_NAME SALARY P_NUMBER P_COUNT
------------- ---------- ---------- ---------- ---------- ----------
30 114 Colmenares 2500 1 3
30 114 Himuro 2600 2 3
30 114 Tobias 2800 3 3
I know how to use cumulative sum in its basic formulation, with code like this:
Table Name: Employees
dept_id salary
-------------
10 1000
10 1000
10 2000
10 3000
20 5000
20 6000
20 NULL
SELECT dept_id,
salary,
SUM(salary) OVER(PARTITION BY dept_id
ORDER BY salary ASC
rows unbounded preceding) cum_sum
FROM Employees;
dept_id salary cum_sum
--------------------------
10 1000 1000
10 1000 2000
10 2000 4000
10 3000 7000
20 5000 5000
20 6000 11000
20 NULL 11000
But how do I limit the cumulative sum to only N preceding rows?
For example, limit cumulative sum to current row and previous two rows.
dept_id salary cum_sum
--------------------------
10 1000 1000
10 1000 2000
10 2000 4000
10 3000 6000
20 5000 5000
20 6000 11000
20 NULL 11000
The SQL syntax is:
SELECT dept_id,
salary,
SUM(salary) OVER(PARTITION BY dept_id
ORDER BY salary ASC
rows between <N> preceding and current row) cum_sum
FROM Employees;
Can you guys help me with this query? I want to modify it so that it only shows me those departments with at least 3 employees from this query (with the 78%), and not from (the original table of employees/department). Every time i try " having COUNT (department_ID) or # the WHERE clause it gives me an error. Do i need to do a 2nd join? Thank you
select *
from
(
SELECT b.employee_id, b.employee_name,b.salary, a.department_id,
NVL(a.department_name, 'N/A') as dept_name,
max(b.salary) over (partition by a.department_id) as max_sal
FROM department a, employee b
WHERE a.department_id(+) = b.department_id
) z
WHERE salary > (max_sal*.78 )
Results:
EMPLOYEE_ID EMPLOYEE_NAME SALARY DEPARTMENT_ID DEPT_NAME MAX_SAL
7566 JONES 3000 10 ACCOUNTING 3000
7886 STEEL 2500 10 ACCOUNTING 3000
7944 LEE 2400 20 RESEARCH 3000
7999 WOLFE 2500 20 RESEARCH 3000
7610 WILSON 3000 20 RESEARCH 3000
7921 JACKSON 2500 30 SALES 3000
7900 FISHER 3000 30 SALES 3000
7788 SCOTT 2500 40 IT 2900
7910 SMITH 2900 40 IT 2900
7603 CLARK 4000 50 EXECUTIVE 5000
7596 JOST 4500 50 EXECUTIVE 5000
7839 KING 5000 50 EXECUTIVE 5000
8000 BREWSTER 2500 N/A 2500
13 rows selected
This are RESULTS I need to get:
EMPLOYEE_ID EMPLOYEE_NAME SALARY DEPARTMENT_ID DEPT_NAME MAX_SAL
7944 LEE 2400 20 RESEARCH 3000
7999 WOLFE 2500 20 RESEARCH 3000
7610 WILSON 3000 20 RESEARCH 3000
7603 CLARK 4000 50 EXECUTIVE 5000
7596 JOST 4500 50 EXECUTIVE 5000
7839 KING 5000 50 EXECUTIVE 5000
6 rows selected
You can do the calculation using an analytic function in another subquery:
select de.*
from (select de.*, count(*) over (partition by department_id) as cnt
from (SELECT e.employee_id, e.employee_name, d.salary, d.department_id,
NVL(d.department_name, 'N/A') as dept_name,
max(e.salary) over (partition by d.department_id) as max_sal
FROM department d JOIN
employee e
ON d.department_id = e.department_id
) de
where salary > max_sal*.78
) de
where cnt >= 3;
The outer join doesn't seem necessary so I replaced it with an inner join and modern join syntax. I also changed the table aliases to be abbreviations for the tables. It makes the code easier to read.