Using SQL to edit salary based on job id - sql

Table: EMPLOYEES
Columns:
EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB_ID, SALARY, COMMISSION_PCT, MANAGER_ID, DEPARTMENT_ID
My current output from the Employees table looks like this:
EMPLOYEE_ID LAST_NAME JOB_ID SALARY
----------- ------------------------- ---------- ----------
205 Higgins AC_MGR 12000
149 Zlotkey SA_MAN 12500
201 Hartstein MK_MAN 13000
102 De Haan AD_VP 17000
101 Kochhar AD_VP 18000
My SQL:
SELECT employee_id,
last_name,
job_id,
salary
from employees
where (job_id like '%VP' OR
Job_id like '%MAN' OR
Job_id like '%MGR')
AND (salary < 6000 OR salary >11000)
order by 4
I need a way to display the salaries before and after a raise, but I also need to be able to give different raises for different job_ids. For example, giving a raise only to the VPs and not to the managers, or giving the VPs a bigger raise than the managers.

One option is to create a CTE which says who gets what; then (outer) join it to the original table. Something like this:
SQL> with raise (job, raise_pct) as
2 (select 'CLERK' , 10 from dual union all
3 select 'ANALYST', 20 from dual
4 )
5 select e.empno, e.ename, e.job, e.sal old_salary,
6 e.sal * (1 + r.raise_pct/100) new_salary
7 from emp e left join raise r on r.job = e.job
8 order by e.job, e.ename;
EMPNO ENAME JOB OLD_SALARY NEW_SALARY
---------- ---------- --------- ---------- ----------
7902 FORD ANALYST 3000 3600
7788 SCOTT ANALYST 3000 3600
7876 ADAMS CLERK 1100 1210
7900 JAMES CLERK 950 1045
7934 MILLER CLERK 1300 1430
7369 SMITH CLERK 800 880
7698 BLAKE MANAGER 2850
7782 CLARK MANAGER 2450
7566 JONES MANAGER 2975
7839 KING PRESIDENT 5000
7499 ALLEN SALESMAN 1600
7654 MARTIN SALESMAN 1250
7844 TURNER SALESMAN 1500
7521 WARD SALESMAN 1250
14 rows selected.
SQL>

Related

Oracle SQL select group function as where clause

I have a simple SQL which result is basic information of employees.
select emp_name, emp_firstname, emp_location, emp_salary from employees e
where e.emp_location = 'XYZ'
Now I ONLY want to get a result of that above mentioned SQL if the sum of ALL employees salary of the location is over 1.000.000 EUR. Otherwise the result should be NULL.
I created a select statement which does analyzes the sum of all employees and returns NULL or the SUM value over 1.000.000 EUR:
select sum(emp_salary) from employees e
where e.emp_location = 'XYZ'
having sum(emp_salary) > 1000000
When I now try to combine both SQL:
select emp_name, emp_firstname, emp_location, emp_salary from employees e
where e.emp_location = 'XYZ'
having sum(emp_salary) > 1000000
I get the error ORA-00937 not a single-group group function
You select non-aggregated fields, but you use no GROUP BY clause. By fixing it, your query should work properly:
SELECT emp_name, emp_firstname, emp_location, SUM(emp_salary) AS emp_salary
FROM employees
WHERE emp_location = 'XYZ'
GROUP BY emp_name, emp_firstname, emp_location
HAVING SUM(emp_salary) > 1000000
Or, if you wish to have sum(emp_salary) by location>1000000, then:
with tb_sal_loc as (
select emp_name, emp_firstname, emp_location, emp_salary
,sum(emp_salary) over (partition by emp_location) loc_salaries
from employees e
where e.emp_location = 'XYZ')
select *
from b_sal_loc
where loc_salaries>1000000;
After your last reply, have you tried the above? This is supposed to do exactly what you have specified in your last reply.
Maybe something like here (10000 limit):
Select EMPNO, ENAME, SAL, LOC, DEPTNO, CASE WHEN DEPT_SAL > 10000 THEN DEPT_SAL END "DEPT_SAL"
From ( Select emp.EMPNO, emp.ENAME, emp.SAL, dept.LOC, dept.DEPTNO, Sum(emp.SAL) OVER(Partition By dept.DEPTNO) "DEPT_SAL"
From emp
Inner Join dept ON(dept.DEPTNO = emp.DEPTNO))
WHERE LOC = 'NEW YORK'
EMPNO ENAME SAL LOC DEPTNO DEPT_SAL
---------- ---------- ---------- ------------- ---------- ----------
7939 HILLER 1300 NEW YORK 10 13850
7934 MILLER 1300 NEW YORK 10 13850
7369 SMITH 800 NEW YORK 10 13850
7902 FORD 3000 NEW YORK 10 13850
7839 KING 5000 NEW YORK 10 13850
7782 CLARK 2450 NEW YORK 10 13850
-- without where condition
Select EMPNO, ENAME, SAL, LOC, DEPTNO, CASE WHEN DEPT_SAL > 10000 THEN DEPT_SAL END "DEPT_SAL"
From ( Select emp.EMPNO, emp.ENAME, emp.SAL, dept.LOC, dept.DEPTNO, Sum(emp.SAL) OVER(Partition By dept.DEPTNO) "DEPT_SAL"
From emp
Inner Join dept ON(dept.DEPTNO = emp.DEPTNO))
EMPNO ENAME SAL LOC DEPTNO DEPT_SAL
---------- ---------- ---------- ------------- ---------- ----------
7939 HILLER 1300 NEW YORK 10 13850
7934 MILLER 1300 NEW YORK 10 13850
7369 SMITH 800 NEW YORK 10 13850
7902 FORD 3000 NEW YORK 10 13850
7839 KING 5000 NEW YORK 10 13850
7782 CLARK 2450 NEW YORK 10 13850
7788 SCOTT 3000 DALLAS 20
7566 JONES 2975 DALLAS 20
7876 ADAMS 1100 DALLAS 20
7654 MARTIN 1250 CHICAGO 30
7521 WARD 1250 CHICAGO 30
7499 ALLEN 1600 CHICAGO 30
7900 JAMES 950 CHICAGO 30
7698 BLAKE 2850 CHICAGO 30
7844 TURNER 1500 CHICAGO 30
... without where condition and without CASE expression:
Select EMPNO, ENAME, SAL, LOC, DEPTNO, DEPT_SAL
From ( Select emp.EMPNO, emp.ENAME, emp.SAL, dept.LOC, dept.DEPTNO, Sum(emp.SAL) OVER(Partition By dept.DEPTNO) "DEPT_SAL"
From emp
Inner Join dept ON(dept.DEPTNO = emp.DEPTNO))
EMPNO ENAME SAL LOC DEPTNO DEPT_SAL
---------- ---------- ---------- ------------- ---------- ----------
7939 HILLER 1300 NEW YORK 10 13850
7934 MILLER 1300 NEW YORK 10 13850
7369 SMITH 800 NEW YORK 10 13850
7902 FORD 3000 NEW YORK 10 13850
7839 KING 5000 NEW YORK 10 13850
7782 CLARK 2450 NEW YORK 10 13850
7788 SCOTT 3000 DALLAS 20 7075
7566 JONES 2975 DALLAS 20 7075
7876 ADAMS 1100 DALLAS 20 7075
7654 MARTIN 1250 CHICAGO 30 9400
7521 WARD 1250 CHICAGO 30 9400
7499 ALLEN 1600 CHICAGO 30 9400
7900 JAMES 950 CHICAGO 30 9400
7698 BLAKE 2850 CHICAGO 30 9400
7844 TURNER 1500 CHICAGO 30 9400

One query with combining data from two tables and grouping (sql, oracle)

I am trying to write which create a view that shows the number of departments for each location (Loc) and the number of employees working in the departments in one query.
Tables are provided below.
Table Dept
DEPTNO
DNAME
LOC
10
ACCOUNTING
NEW YORK
20
RESEARCH
DALLAS
30
SALES
CHICAGO
40
OPERATIONS
BOSTON
50
RISK
BOSTON
Table Emp
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
9901 Kowalski SALESMAN 9345 23-JAN-90 300 100 12
7369 SMITH CLERK 7902 17-MAR-80 15355.58 20
7499 ALLEN SALESMAN 7698 20-MAR-81 1600 300 30
7521 WARD SALESMAN 7698 22-MAR-81 1250 500 30
7566 JONES MANAGER 7839 02-MAR-81 57103.26 20
7654 MARTIN SALESMAN 7698 28-MAR-81 1250 1400 30
7698 BLAKE MANAGER 7839 01-MAR-81 2850 30
7782 CLARK MANAGER 7839 09-MAR-81 2450 10
7788 SCOTT ANALYST 7566 09-MAR-82 57583.15 20
7839 KING PRESIDENT 17-MAR-81 5000 10
7844 TURNER SALESMAN 7698 08-MAR-81 1500 0 30
7876 ADAMS CLERK 7788 12-MAR-83 21113.82 20
7900 JAMES CLERK 7698 03-MAR-81 950 30
7902 FORD ANALYST 7566 03-MAR-81 57583.15 20
7934 MILLER CLERK 7782 23-MAR-82 1300 10
The output should be
LOC NO_DEP NO_EMP
------------- ---------- ----------
NEW YORK 1 3
DALLAS 1 1
CHICAGO 1 5
BOSTON 2 6
So far I was able to create two separate queries which are provided below and which gives this result however I must do it in a one query which will give output in one table.
SELECT DISTINCT d.Loc, Count(d.Deptno) AS No_Dep, d.Deptno
FROM Dept d
GROUP BY d.Loc, d.Deptno;
SELECT DISTINCT COUNT(e.Empno) OVER (PARTITION BY e.Deptno) AS No_Emp, e.Deptno
FROM Emp e;
Correct solution is
SELECT d.LOC, COUNT(DISTINCT d.DEPTNO) AS NO_DEP, COUNT(e.EMPNO) AS NO_EMP
FROM DEPT d
LEFT JOIN EMP e ON d.DEPTNO = e.DEPTNO
GROUP BY D.LOC;
You first need to join them and then and then need to do the aggregation -
SELECT D.LOC, COUNT(DISTINCT DEPTNO) NO_DEP, COUNT(EMPNO) NO_EMP
FROM DEPT D
JOIN EMP E ON D.DEPTNO = E.DEPTNO
GROUP BY D.LOC;
you can use "group by" and "having" to solve such queries
The HAVING clause is used instead of WHERE with aggregate functions. While the GROUP BY Clause groups rows that have the same values into summary rows. The having clause is used with the where clause in order to find rows with certain conditions. The having clause is always used after the group By clause.
example:
select D.LOC AS LOC, COUNT(D.DEPTNO) AS NO_DEP, COUNT(distinct E.EMPNO) AS NO_EMP
from Dept D, Emp E
where D.DEPTNO=E.DEPTNO
group by D.LOC;

How to find minimum and maximum of a column with all other columns from the table

How to get MIN(salary) and MAX(salary) and all other columns such as name, DOB, phone number ...etc in oracle SQL query.
I have tried the following and its working fine but is there any other way using analytical functions or something like that .
SELECT
a.*
FROM
employees a
JOIN (
SELECT
MIN(salary) min_sal,
department_id
FROM
employees
GROUP BY
department_id
) b ON a.salary = min_sal
AND a.department_id = b.department_id
UNION
SELECT
a.*
FROM
employees a
JOIN (
SELECT
MAX(salary) max_sal,
department_id
FROM
employees
GROUP BY
department_id
) b ON a.salary = max_sal
AND a.department_id = b.department_id;
Something like this, I presume (based on Scott's sample emp table); query returns min and max salary per each department (that's what partition by clause says):
SQL> select deptno, empno, ename, job, sal,
2 min(sal) over (partition by deptno) min_sal,
3 max(sal) over (partition by deptno) max_sal
4 from emp
5 order by deptno, sal;
DEPTNO EMPNO ENAME JOB SAL MIN_SAL MAX_SAL
---------- ---------- ---------- --------- ---------- ---------- ----------
10 7934 MILLER CLERK 1495 1495 5750
10 7782 CLARK MANAGER 2818 1495 5750
10 7839 KING PRESIDENT 5750 1495 5750
20 7369 SMITH CLERK 920 920 3450
20 7876 ADAMS CLERK 1265 920 3450
20 7566 JONES MANAGER 3421 920 3450
20 7788 SCOTT ANALYST 3450 920 3450
20 7902 FORD ANALYST 3450 920 3450
30 7900 JAMES CLERK 998 998 2993
30 7654 MARTIN SALESMAN 1313 998 2993
30 7521 WARD SALESMAN 1313 998 2993
30 7844 TURNER SALESMAN 1575 998 2993
30 7499 ALLEN SALESMAN 1680 998 2993
30 7698 BLAKE MANAGER 2993 998 2993
14 rows selected.
SQL>

How can we handle multiple rows returned from a subquery inside a case statement?

Write a SELECT query if department id provided at run time is 100 then it will return all the employee details those belong to department 100 else i wanted to print all the employees from employee table.
i have written below query :-
SELECT * FROM EMPLOYEES
WHERE department_id IN (
CASE &InputDept
WHEN 100 THEN 100
ELSE (SELECT DISTINCT department_id FROM DEPARTMENTS) END ) ;
This works fine when input is 100 but returned "Single-row subquery returns more than one row".
i understand that case is a statement which works like "if-then-else" with single value, also i tried with decode but no luck.
This can be easily done in PL/SQL , but is this possible with SELECT query?
Skip the case expression, use regular AND/OR instead:
SELECT * FROM EMPLOYEES
WHERE (&InputDept = 100 and department_id = 100)
OR (&InputDept <> 100 and department_id IN
(SELECT department_id FROM DEPARTMENTS)) ;
To handle NULL InputDept:
SELECT * FROM EMPLOYEES
WHERE (&InputDept = 100 and department_id = 100)
OR ((&InputDept <> 100 or &InputDept IS NULL) AND department_id IN
(SELECT department_id FROM DEPARTMENTS)) ;
It's better to use a query like this:
SELECT * FROM EMPLOYEES
WHERE department_id = CASE &InputDept WHEN 100 THEN 100 END
UNION ALL
SELECT * FROM EMPLOYEES
WHERE (&InputDept != 100 or &InputDept is NULL)
AND department_id IN (SELECT DISTINCT department_id FROM DEPARTMENTS);
Do not forget about employees without department_id, ie NULLs.
This query will be optimized by optimizer at runtime to do not execute unneeded part of union all
Yet another alternative (example based on Scott's sample schema, ran in SQL*Plus):
SQL> select *
2 from emp
3 where deptno in (select deptno from dept
4 where &&inputdept <> 10
5 union all
6 select &&inputdept from dual
7 where &&inputdept = 10
8 );
Enter value for inputdept: 10
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------- ---------- ---------- ----------
7782 CLARK MANAGER 7839 09.06.81 2450 10
7839 KING PRESIDENT 17.11.81 5000 10
7934 MILLER CLERK 7782 23.01.82 1300 10
SQL> undefine inputdept
SQL> /
Enter value for inputdept: 25
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17.12.80 800 20
7499 ALLEN SALESMAN 7698 20.02.81 1600 300 30
7521 WARD SALESMAN 7698 22.02.81 1250 500 30
7566 JONES MANAGER 7839 02.04.81 2975 20
7654 MARTIN SALESMAN 7698 28.09.81 1250 1400 30
7698 BLAKE MANAGER 7839 01.05.81 2850 30
7782 CLARK MANAGER 7839 09.06.81 2450 10
7788 SCOTT ANALYST 7566 09.12.82 3000 20
7839 KING PRESIDENT 17.11.81 5000 10
7844 TURNER SALESMAN 7698 08.09.81 1500 0 30
7876 ADAMS CLERK 7788 12.01.83 1100 20
7900 JAMES CLERK 7698 03.12.81 950 30
7902 FORD ANALYST 7566 03.12.81 3000 20
7934 MILLER CLERK 7782 23.01.82 1300 10
14 rows selected.
SQL>

ORA-00913: too many values error when I run a query in SQL*Plus

I am trying to get the dname, loc, and count the ename's, plus I want to include the sal from the table. Can someone tell me what I am doing wrong.
Heres my statement with the error I get
SQL> select dname, loc, (select count(ename), sal from emp where DEPTNO = dept.deptno) as Number_of_people from dept;
select dname, loc, (select count(ename), sal from emp where DEPTNO = dept.deptno) as Number_of_people from dept
*
ERROR at line 1:
ORA-00913: too many values
SQL>
Heres my table
SQL> select empno, ename, job, hiredate, sal from emp;
EMPNO ENAME JOB HIREDATE SAL
---------- ---------- --------- --------- ----------
7839 KING PRESIDENT 17-NOV-81 5000
7698 BLAKE MANAGER 01-MAY-81 2850
7782 CLARK MANAGER 09-JUN-81 2450
7566 JONES MANAGER 02-APR-81 2975
7654 MARTIN SALESMAN 28-SEP-81 1250
7499 ALLEN SALESMAN 20-FEB-81 1600
7844 TURNER SALESMAN 08-SEP-81 1500
7900 JAMES CLERK 03-DEC-81 950
7521 WARD SALESMAN 22-FEB-81 1250
7902 FORD ANALYST 03-DEC-81 3000
7369 SMITH CLERK 17-DEC-80 800
EMPNO ENAME JOB HIREDATE SAL
---------- ---------- --------- --------- ----------
7788 SCOTT ANALYST 09-DEC-82 3000
7876 ADAMS CLERK 12-JAN-83 1100
7934 MILLER CLERK 23-JAN-82 1300
14 rows selected.
SQL>
Heres the second table
SQL> select * from dept;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL>
To get number of people and total Salary, try this...
select dept.dname, dept.loc,
count(emp.ename) as Number_of_people, sum(emp.sal) as Total_Salary
from emp
join dept on emp.DEPTNO = dept.deptno
group by dept.dname,dept.loc
You can get other things as well
select dept.dname, dept.loc,
count(emp.ename) as Number_of_people,
sum(emp.sal) as Total_Salary,
avg(emp.sal) as Average_salary,
min(emp.hiredate) as First_dept_hire,
max(emp.hireDate) as Last_dept_hire
from emp
join dept on emp.DEPTNO = dept.deptno
group by dept.dname,dept.loc
The scalar (inline) cursor can only have only one value in its projection.
If you want to have more than one value, use a join and aggregate all the values, as Sparky suggests.