SQL Grouping of Salaries - sql

I have a question to ask and I am supposed to create a query which shows:
MIN(lastname) MAX(firstname) SUM(salary) AVG(salary)
---------------------------------------------------------------
DAVIES TRINA 17500 3500
This was the query/queries I created:
SQL> SELECT MIN(LASTNAME), MAX(FIRSTNAME), SUM(SALARY), AVG(SALARY)
2 FROM EMPLOYEES
3 GROUP BY JOB_ID;
SQL> SELECT MIN(LASTNAME), MAX(FIRSTNAME), SUM(SALARY), AVG(SALARY)
2 FROM EMPLOYEES
3 GROUP BY JOB_ID, MANAGER_ID;
But I get multiple rows shown to me and in the part where DAVIES TRINA was shown the SUM and AVG salary is different and I am unsure how they were grouped.
MIN(LASTNAME) MAX(FIRSTNAME) SUM(SALARY) AVG(SALARY)
---------- ---------- ----------- -----------
ERNST DIANA 10200 5100
HIGGINS SHELLEY 12000 12000
GIETZ WILLIAM 8300 8300
MOURGOS KEVIN 5800 5800
WHALEN JENNIFER 4400 4400
DE HAAN NENA 34000 17000
ZLOTKEY ELENI 10500 10500
HARTSTEIN MICHAEL 13000 13000
KING STEVEN 24000 24000
ABEL KIMBERLEY 26600 8866.66667
FAY PAT 6000 6000
**DAVIES TRINA 11700 2925**
What am I doing wrong?
MORE INFO BELOW:
EMPLOYEE_ID FIRSTNAME LASTNAME JOB_ID SALARY MANAGER_ID DEPARTMENT_ID
100 STEVEN KING AD_PRES 24000 90
101 NENA KOCHAR AD_VP 17000 100 90
102 LEX DE HAAN AD_VP 17000 100 90
103 ALEXANDER HUNOLD IT_PROG 101 60
104 BRUCE ERNST IT_PROG 6000 102 60
107 DIANA LORENTZ IT_PROG 4200 103 60
124 KEVIN MOURGOS ST_MAN 5800 100 50
141 TRINA RAJS ST_CLERK 3500 124 50
142 CURTIS DAVIES ST_CLERK 3100 124 50
143 RANDALL MATOS ST_CLERK 2600 124 50
144 PETER VARGAS ST_CLERK 2500 124 50
EMPLOYEE_ID FIRSTNAME LASTNAME JOB_ID SALARY MANAGER_ID DEPARTMENT_ID
149 ELENI ZLOTKEY SA_MAN 10500 100 80
174 ELLEN ABEL SA_REP 11000 149 50
176 JONATHAN TAYLOR SA_REP 8600 149 80
178 KIMBERLEY GRANT SA_REP 7000 149
200 JENNIFER WHALEN AD_ASST 4400 101 10
201 MICHAEL HARTSTEIN MK_MAN 13000 100 20
202 PAT FAY MK_REP 6000 201 20
205 SHELLEY HIGGINS AC_MGR 12000 101 110
206 WILLIAM GIETZ AC_ACCOUNT 8300 205 110

If you provide the proper data that is, the data before running the query/queries and also tell why it should be 17500(sum) and 3500(avg) then you have more chances to get answers.
In the 1st query you are grouping based on JOB_ID. That means for all similar JOB_IDs (in case of SUM(SALARY)) it will select the the values of SALARY column and SUM the values for each different JOB_ID.
Example:
JOB_ID SALARY
1 200
2 300
1 150
2 100
3 270
If you run the following query:
Select JOB_ID,SUM(SALARY) FROM Table GROUP BY JOB_ID
Output:
JOB_ID SALARY
1 350
2 400
3 270

Related

avg sql function [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I have a table employees
EMPLOYEE_ID FIRST_NAME LAST_NAME HIRE_DATE JOB_ID SALARY DEPARTMENT_ID
-------------------------------------------------------------------------------------------
100 Steven King 17-JUN-03 AD_PRES 24000 90
101 Neena Kochhar 21-SEP-05 AD_VP 17000 90
102 Lex De Haan 13-JAN-01 AD_VP 17000 90
103 Alexander Hunold 03-JAN-06 IT_PROG 9000 60
104 Bruce Ernst 21-MAY-07 IT_PROG 6000 60
105 David Austin 25-JUN-05 IT_PROG 4800 60
106 Valli Pataballa 05-FEB-06 IT_PROG 4800 60
107 Diana Lorentz 07-FEB-07 IT_PROG 4200 60
109 Daniel Faviet 16-AUG-02 FI_ACCOUNT 9000 100
110 John Chen 28-SEP-05 FI_ACCOUNT 8200 100
111 Ismael Sciarra 30-SEP-05 FI_ACCOUNT 7700 100
112 Jose Manuel Urman 07-MAR-06 FI_ACCOUNT 7800 100
113 Luis Popp 07-DEC-07 FI_ACCOUNT 6900 100
and table departments
DEPARTMENT_ID DEPARTMENT_NAME
-------------------------------
30 Purchasing
50 Shipping
60 IT
90 Executive
100 Finance
I need to write 3 queries:
Get department name and number of employees in each department sorting ascending
I tried this
select count(e.employee_id), d.department_name
from t_employees e, t_departments d
where d.department_id = e.department_id
group by e.department_name
order by count(e.employee_id);
Not sure if it will work since I can not really try it.
Get department name and average salary where average salary by department is more or equal 5000
Result table
DEPARTMENT_NAME AVERAGE_SALARY
---------------------------------
Executive 19333,333
IT 5760
Finance 7920`
select d.department_name, AVG(e.salary) as AVARAGE_SALARY
from t_departments d, t_employees e
where d.department_id = e.department_id
and avg(e.salary) >= '5000'
group by d.department_name;
Get first name and last name of employees who have salary bigger than the average salary from the department they work in
Result table
FIRST_NAME LAST_NAME
---------------------------------
Steven King
Alexander Hunold
Bruce Ernst
Daniel Faviet
John Chen
I have no code for this one.
You're quite close.
I don't have your tables so I'll use Scott's sample schema. Try to apply it to your data model.
First:
SQL> select d.dname, count(*) cnt
2 from emp e join dept d on e.deptno = d.deptno
3 group by d.dname
4 order by cnt desc;
DNAME CNT
-------------- ----------
SALES 6
RESEARCH 5
ACCOUNTING 3
Second: not where, but having:
SQL> select d.dname, avg(e.sal) avg_sal
2 from emp e join dept d on e.deptno = d.deptno
3 group by d.dname
4 having avg(e.sal) > 2000; --> this
DNAME AVG_SAL
-------------- ----------
ACCOUNTING 2916,66667
RESEARCH 2175
SQL>
Third:
SQL> with avgsal as
2 (select deptno,
3 round(avg(sal), 1) avgsal
4 from emp
5 group by deptno
6 )
7 select e.deptno, e.ename, e.sal, a.avgsal
8 from emp e join avgsal a on a.deptno = e.deptno
9 where e.sal > a.avgsal
10 order by e.deptno;
DEPTNO ENAME SAL AVGSAL
---------- ---------- ---------- ----------
10 KING 5000 2916,7
20 JONES 2975 2175
20 SCOTT 3000 2175
20 FORD 3000 2175
30 ALLEN 1600 1566,7
30 BLAKE 2850 1566,7
6 rows selected.
SQL>

Confusion with the behavior of HAVING clause

I am not able to understand the behavior of the following query:
select max(avg(salary)) from employees
group by first_name
having avg(salary) >= max(salary);
It prints out the result as 17000. But if max(salary) is 24000 shouldn't there be empty result. If I replace "">="" with ">" it prints the result as NULL.
And if I replace ">=" with "<", then 13100 is printed in the result.
Below is the employees table:
TJ 2100
Steven 2200
Hazel 2200
James 2400
Ki 2400
Karen 2500
James 2500
Joshua 2500
Peter 2500
Martha 2500
Randall 2500
Guy 2600
Randall 2600
Donald 2600
Douglas 2600
Irene 2700
John 2700
Sigal 2800
Mozhe 2800
Girard 2800
Vance 2800
Shelli 2900
Michael 2900
Timothy 2900
Anthony 3000
Kevin 3000
Alex 3100
Curtis 3100
Jean 3100
Alana 3100
Julia 3200
Stephen 3200
Winston 3200
Samuel 3200
Laura 3300
Jason 3300
Julia 3400
Trenna 3500
Renske 3600
Jennife 3600
Kelly 3800
Britney 3900
Sarah 4000
Alexis 4100
Diana 4200
Nandita 4200
Jennife 4400
David 4800
Valli 4800
Kevin 5800
Bruce 6000
Pat 6000
Sundita 6100
Amit 6200
Charles 6200
Sundar 6400
Shanta 6500
Susan 6500
David 6800
Luis 6900
Oliver 7000
Sarath 7000
Kimbe 7000
Mattea 7200
Eliza 7300
William 7400
Nanette 7500
Louise 7500
Ismael 7700
Jose 7800
Payam 7900
Matthew 8000
Christ 8000
Lindsey 8000
John 8200
Adam 8200
William 8300
Jack 8400
Jonath 8600
Alyssa 8800
Alex 9000
Daniel 9000
Peter 9000
Allan 9000
Patrick 9500
Danie 9500
David 9500
Tayler 9600
Hermann 10000
Harris 10000
Janette 10000
Peter 10000
Clara 10500
Eleni 10500
Gerald 11000
Den 11000
Ellen 11000
Lisa 11500
Alberto 12000
Shelley 12008
Nancy 12008
Michael 13000
Karen 13500
John 14000
Lex 17000
Neena 17000
Steven 24000
You are doing Group By First_name, in your table,
For Neena, max(salary) = 17000 and avg(salary)=17000,
So, >= matches the condition in the query and 17000 is returned.
Where as replacing >= with > evaulated to NULL.
For Steven, Max(salary)=24000, AVG(salary)=(24000+2200)/2=13100
So replacing >= with < returns 13100
Note : Grouping by ColumnName here first_name plays the key role
here. All the aggregate functions in SELECT as well as having clause,
are applied per employee and not on the whole table.
If you want to compare an employee's mean salary (does this really make sense? Surely an employee only has one salary at a point in time?) then this might help
WITH
employees (first_name,salary)
AS
(SELECT 'TJ',2100 FROM dual UNION ALL
SELECT 'Steven',2200 FROM dual UNION ALL
SELECT 'Hazel',2200 FROM dual UNION ALL
SELECT 'James',2400 FROM dual UNION ALL
SELECT 'Ki',2400 FROM dual UNION ALL
SELECT 'Karen',2500 FROM dual UNION ALL
SELECT 'James',2500 FROM dual UNION ALL
SELECT 'Joshua',2500 FROM dual UNION ALL
SELECT 'Peter',2500 FROM dual UNION ALL
SELECT 'Martha',2500 FROM dual
)
SELECT
first_name
,mean_salary_all_emps
,AVG(salary)
FROM
(SELECT
first_name
,salary
,AVG(salary) OVER () mean_salary_all_emps
FROM
employees
)
WHERE 1=1
GROUP BY
first_name
,mean_salary_all_emps
HAVING AVG(salary) > mean_salary_all_emps
;

How to display department (once) and list of all employees working in that department?

For the schema epartments(department_id, department_name) employees(last_name, department_id, salary)
I want to display the department_id, department_name, count(employees),avg(salary),last_name,salary
I have tried using the following query
SELECT d1.department_id,d1.department_name,d1."count",d1."avg",e.last_name,e.salary
FROM employees e
INNER JOIN (SELECT d.department_id,d.department_name,count(e.last_name) AS "count",round(avg(e.salary),2) AS "avg"
FROM employees e,departments d
WHERE e.department_id=d.department_id
GROUP BY d.department_id,d.department_name) d1
ON e.department_id=d1.department_id;
While it displays the correct output it is not in the format I want.
The above query gives output as
90 Executive 3 19333.33 King 24000
90 Executive 3 19333.33 Kochhar 17000
90 Executive 3 19333.33 De Haan 17000
60 IT 3 6400 Hunold 9000
60 IT 3 6400 Ernst 6000
60 IT 3 6400 Lorentz 4200
50 Shipping 5 3500 Mourgos 5800
While it should be like
90 Executive 3 19333.33 King 24000
Kochhar 17000
De Haan 17000
60 IT 3 6400 Hunold 9000
Ernst 6000
Lorentz 4200
50 Shipping 5 3500 Mourgos 5800
If you really want to show something like '' instead of those data in your query, I think you can use ROW_NUMBER() for that like this:
CASE
WHEN (ROW_NUMBER() OVER (PARTITION BY d1.department_id
ORDER BY d1.department_id)) = 1 THEN
d1.department_id
ELSE
Null
END
for columns: d1.department_id,d1.department_name,d1."count",d1."avg".

query on hr schema

I am new to SQL and am practicing on the HR schema available on Oracle 10g XE.
This is the question:
Write a query to select the name, job, and salary and department number of all employees except Sales Rep from department number 80.
My query is this:
select first_name||' '||last_name "Employee Name"
, job_id, salary, department_id
from employees
where not( job_id='SA_REP' and department_id=80 )
order by department_id;
Output:
Employee Name JOB_ID SALARY DEPARTMENT_ID
---------------------------------------------- ---------- ---------- -------------
Jennifer Whalen AD_ASST 4400 10
Michael Hartstein MK_MAN 13000 20
Pat Fay MK_REP 6000 20
Den Raphaely PU_MAN 11000 30
Alexander Khoo PU_CLERK 3100 30
Shelli Baida PU_CLERK 2900 30
Sigal Tobias PU_CLERK 2800 30
Guy Himuro PU_CLERK 2600 30
Karen Colmenares PU_CLERK 2500 30
Susan Mavris HR_REP 6500 40
Matthew Weiss ST_MAN 8000 50
Adam Fripp ST_MAN 8200 50
Payam Kaufling ST_MAN 7900 50
Shanta Vollman ST_MAN 6500 50
Kevin Mourgos ST_MAN 5800 50
Julia Nayer ST_CLERK 3200 50
Irene Mikkilineni ST_CLERK 2700 50
James Landry ST_CLERK 2400 50
Steven Markle ST_CLERK 2200 50
Laura Bissot ST_CLERK 3300 50
Mozhe Atkinson ST_CLERK 2800 50
James Marlow ST_CLERK 2500 50
TJ Olson ST_CLERK 2100 50
Jason Mallin ST_CLERK 3300 50
Michael Rogers ST_CLERK 2900 50
Ki Gee ST_CLERK 2400 50
Hazel Philtanker ST_CLERK 2200 50
Renske Ladwig ST_CLERK 3600 50
Stephen Stiles ST_CLERK 3200 50
John Seo ST_CLERK 2700 50
Joshua Patel ST_CLERK 2500 50
Trenna Rajs ST_CLERK 3500 50
Curtis Davies ST_CLERK 3100 50
Randall Matos ST_CLERK 2600 50
Peter Vargas ST_CLERK 2500 50
Winston Taylor SH_CLERK 3200 50
Jean Fleaur SH_CLERK 3100 50
Martha Sullivan SH_CLERK 2500 50
Girard Geoni SH_CLERK 2800 50
Nandita Sarchand SH_CLERK 4200 50
Alexis Bull SH_CLERK 4100 50
Julia Dellinger SH_CLERK 3400 50
Anthony Cabrio SH_CLERK 3000 50
Kelly Chung SH_CLERK 3800 50
Jennifer Dilly SH_CLERK 3600 50
Timothy Gates SH_CLERK 2900 50
Randall Perkins SH_CLERK 2500 50
Sarah Bell SH_CLERK 4000 50
Britney Everett SH_CLERK 3900 50
Samuel McCain SH_CLERK 3200 50
Vance Jones SH_CLERK 2800 50
Alana Walsh SH_CLERK 3100 50
Kevin Feeney SH_CLERK 3000 50
Donald OConnell SH_CLERK 2600 50
Douglas Grant SH_CLERK 2600 50
Alexander Hunold IT_PROG 9000 60
Bruce Ernst IT_PROG 6000 60
David Austin IT_PROG 4800 60
Valli Pataballa IT_PROG 4800 60
Diana Lorentz IT_PROG 4200 60
Hermann Baer PR_REP 10000 70
John Russell SA_MAN 14000 80
Karen Partners SA_MAN 13500 80
Alberto Errazuriz SA_MAN 12000 80
Gerald Cambrault SA_MAN 11000 80
Eleni Zlotkey SA_MAN 10500 80
Steven King AD_PRES 24000 90
Neena Kochhar AD_VP 17000 90
Lex De Haan AD_VP 17000 90
Nancy Greenberg FI_MGR 12000 100
Daniel Faviet FI_ACCOUNT 9000 100
John Chen FI_ACCOUNT 8200 100
Ismael Sciarra FI_ACCOUNT 7700 100
Luis Popp FI_ACCOUNT 6900 100
Jose Manuel Urman FI_ACCOUNT 7800 100
Shelley Higgins AC_MGR 12000 110
William Gietz AC_ACCOUNT 8300 110
77 rows selected.
I am not however getting the desired output,as the output is not displaying this row:
Employee Name JOB_ID SALARY DEPARTMENT_ID
---------------------------------------------- ---------- ---------- -------------
Kimberely Grant SA_REP 7000
This record does not have a department number, but it should also be displayed in the output along with the other 77 rows. Can anyone please point out where i am going wrong with the query?
So the goal is to get a list of all employees except those who are sales reps and in department 80? That is, you still want employees in department 80 (as well as all other departments) unless they are sales reps, and sales reps unless they are in department 80?
In Oracle, the comparison of a NULL value with anything else returns NULL rather than TRUE or FALSE. So you'll want to either: (a) add an explicit IS NULL condition (or IS NOT NULL, depending on your query parameters) or (b) use the COALESCE() (or NVL()) function. Something like this:
SELECT first_name || ' ' || last_name "Employee Name"
, job_id, salary, department_id
FROM employees
WHERE job_id != 'SA_REP'
OR department_id IS NULL
OR department_id != 80
ORDER BY department_id;
or:
SELECT first_name || ' ' || last_name "Employee Name"
, job_id, salary, department_id
FROM employees
WHERE job_id != 'SA_REP'
OR COALESCE(department_id, 0) != 80
ORDER BY department_id;
Thanks to #DavidFaber for confirming my original thought. The not that you have in your where clause isn't playing nice with the department_id = 80 portion, because of the empty value for Kimbereley Grant in department_id. Basically, the "not (job_id='SA_REP' and department_id=80)" becomes "not job_id='SA_REP' or not department_id=80", hence "job_id != 'SA_REP' or department_id != 80".
Kimberely Grant fails the first check (her job_id is in fact SA_REP) and the second check should result in essentially, "Unknown" (her department_id is not 80, but it's not not 80 either, it's NULL). As a result, you have false or "Unknown" which becomes false.
The fix is what #Ponder suggested. Add a null check on department_id:
not (job_id='SA_REP' and department_id=80 and department_id is not null)
which is equivalent to:
not (job_id='SA_REP' and department_id=80) or department_id is null
Thanks every one. I am able to get the required output now with this query:
SELECT first_name || ' ' || last_name "Employee Name"
, job_id, salary, department_id
FROM employees
WHERE job_id != 'SA_REP'
OR department_id IS NULL
OR department_id != 80
ORDER BY department_id;
Many Thanks again.Cheers.

SQL check constraint multiple conditions

The team has decided that, except for the gm and catchers, a player
name should not exceed 10 letters. Implement this as a check constraint.
Table: (table name: empbbb02)
EMPNO ENAME
EMPNO ENAME POS BOSS HIREDATE SAL DEPTNO INCENTIVES
----- ---------- ------------ ---- --------- ---------- ---------- ----------
712 rickey gm 01-JAN-98 10000 40
735 lasorda coach 712 10-JAN-98 2000 40
707 bochy coach 712 11-JAN-98 2000 40
798 berra coach 712 12-JAN-98 2000 40
782 musial right field 707 01-FEB-98 42000 20
763 gehrig first base 735 11-MAR-98 85000 10
777 minoso shortstop 735 05-MAY-98 85000 10 6000
721 sandberg second base 735 28-FEB-98 25000 10
788 cey third base 735 10-JAN-99 15000 10 8000
720 williams left field 707 05-JAN-99 15000 20
755 johnson pitcher 798 08-NOV-98 50000 30
You need to add a check constraint to your table:
alter table empbbb02 add check (char_length(ename) <= 10 or pos in ('gm','catcher'))