ORACLE: multiple column subqueries - oracle

This is from Oracle Database 10g: SQL Fundamentals.
Original Oracle textbook.
Francly speaking, this all is actual so far.
There is a task which troubles me:
Display the last name, department name, and salary of any employee whose salary and commission match the salary and commission of many employee located in location ID 1700.
The topic to be learned is multiple column subqueries. This mean that we can't deviate from the offered model which is:
SELECT column, column, ...
FROM table
WHERE (column, column, ...) IN
(SELECT column, column, ...
FROM table
WHERE condition);
Well, my database:
describe employees
Name Null Type
-------------- -------- ------------
EMPLOYEE_ID NOT NULL NUMBER(6)
FIRST_NAME VARCHAR2(20)
LAST_NAME NOT NULL VARCHAR2(25)
EMAIL NOT NULL VARCHAR2(25)
PHONE_NUMBER VARCHAR2(20)
HIRE_DATE NOT NULL DATE
JOB_ID NOT NULL VARCHAR2(10)
SALARY NUMBER(8,2)
COMMISSION_PCT NUMBER(2,2)
MANAGER_ID NUMBER(6)
DEPARTMENT_ID NUMBER(4)
describe departments
Name Null Type
--------------- -------- ------------
DEPARTMENT_ID NOT NULL NUMBER(4)
DEPARTMENT_NAME NOT NULL VARCHAR2(30)
MANAGER_ID NUMBER(6)
LOCATION_ID NUMBER(4)
There is a solution:
select
e.last_name,
d.department_name,
e.salary
from employees e, departments d
where e.department_id = d.department_id
and (salary, nvl(commission_pct, 0)) in
(select salary, nvl(commission_pct, 0)
from employees e, departments d
where e.department_id = d.department_id
and d.location_id = 1700);
SELECTED 36 ROWS.
Well, I started checking. It seems that employees from location 1700 duplicated against themselves.
Look: we take the whole list of employees and then juxtapose it with employees from location 1700. Of course, there will be duplicates.
I have prepared an excel file with some data (all employees, employees from location 1700, the result of my own desired result etc.). In the file it is more picturesque, with examples and so on. Please, have a look.
This is the file: https://skydrive.live.com/redir?resid=8CDFFBA921B002FE!150&authkey=!ADMRAE466BIunQM
Well, what I would like to do is to control that no employee is compared with themselves.
This was my variant bevore I checked the solution.
select lnme, dpt, slry
from
(
select
employee_id eid,
last_name lnme,
salary slry,
nvl(commission_pct,0) cpct,
d.department_name dpt,
location_id
from employees e
left join departments d
on e.department_id = d.department_id
)
where (slry, cpct) in
(select
employee_id ide,
salary slry,
nvl(commission_pct,0) cpct
from employees e
join departments d
on e.department_id = d.department_id and location_id = 1700)
and ide <> eid
I wanted to make sure that no employee is compared with the same employee. But I failed.
Could you comment on all this situation:
1. Whether I'm completely wrong and the solution of Oracle is perfect.
2. If Oracle is wrong, could you help me with this code?
Thank you in advance.

The question asks you to identify any employee whose salary and commission matches any combination of salary and salary of employees in Department 1700. The question doesn't say to exclude employees from that department. So it is quite correct for them to appear in the result set.
"One employee can't match themselves."
You're not matching employees, you're matching salaries . It just so happens that the list of target salaries is generated from a sub-query on department 1700: it could just as easily be a list of numbers from a CSV file.
Let's have a thought experiment. There are three employees in department 1700:
name | salary | comm
-----------+---------+-----
CHIP | 10,100 | 0
RUNCITER | 12,200 | 0
CONLEY | 10,500 | 0
Nobody else in the company earns above 10K.
So what is the answer to the question: how many employee have a salary and commission which match the salary and commission of any employee located in department 1700?
Three
Zero
Then Joe gets a modest raise and the salaries look like this:
name | salary | comm
-----------+---------+-----
CHIP | 10,500 | 0
RUNCITER | 12,200 | 0
CONLEY | 10,500 | 0
So what is the answer to the same question now?
Still three
Two
The answer is 'three' in both cases.
Why?
Because SQL is a set-based programming language, and the set of all employees who earn the exact salary and commission as employees in department 1700 must include all employees who work in department 1700.
There is a different set, which is the set of all employees who earn the exact salary and commission as employees in department 1700 who don't themselves work in department 1700. But that is not the set the SQL Fundamentals quiz is looking for.

Related

Find out employees average Salary greater than 8000 within their Department

I am trying to find the employees average salary greater than 8000 within their department
I got the avg(salary) within the department greater than 8000 but could not display the names
select avg(salary) from employees group by department_id having avg(salary)> 8000
it show the employees name
Try this:
Select department_id, emp_name, salary from
(select department_id, emp_name, salary, avg(salary) over(partition by department_id) as avg_salary
from employees)
Where avg_salary >= 8000
AND salary >= 8000; -- ADDED THIS CONDITION
Above query will return all the employees within the department having average salaries of employees greater than 8000 with department id, employee name and their salary.
Cheers!!

Find second highest salary in each department using rank/dense_rank in hive

These were the two questions asked to me during an interview but only condition is to use rank/dense_rank.
Find second highest salary in each department using rank/dense_rank in
hive.
When there are sufficient records in each department.
When there is only 1 record in few departments.
Guide me if this is even valid or not.
If yes then what should be the queries for the same.
If you need to select all second salary employees then use
dense_rank() over(partition by department order by salary desc) = 2 filter. It will return all employees with second salary.
When there is only 1 record in the department (no second salary exists, one employee in the department), it will be ranked 1 and you will get no records for that department filtering by dense_rank = 2.
If you need to select only one record (not all employees) with second salary then row_number() over(partition by department order by salary desc) = 2 will work, but it will pick one random employee with second salary if there are many employees with second salary. Only one record will be marked with row_number = 2.
Try this:
WITH RESULT AS
(
SELECT salary, DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS SecondHighest FROM Employee
)
SELECT IFNULL(( SELECT salary FROM RESULT WHERE SecondHighest = 2 ORDER BY salary) , NULL) as SecondHighestSalary

Oracle : It give a error in a dynamic view

I have two table one is employee and one is department. I am creating the dynamic view that will rank all departments by salary. The view should pull information from Department and Employee, sum the salary by department, and rank the department by salary.
CREATE TABLE DEPARTMENT
(DEPARTMENT_ID NUMBER PRIMARY KEY,
DEPARTMENT_NAME VARCHAR(30) NOT NULL
);
CREATE TABLE JOBS
(JOB_ID NUMBER PRIMARY KEY,
JOB_TITLE VARCHAR(35) NOT NULL,
MIN_SALARY DECIMAL NOT NULL,
MAX_SALARY DECIMAL NOT NULL
);
CREATE TABLE EMPLOYEES
(EMPLOYEE_ID NUMBER PRIMARY KEY,
FIRST_NAME VARCHAR(20) NOT NULL,
LAST_NAME VARCHAR(25) NOT NULL,
EMAIL VARCHAR(25) NOT NULL,
PHONE_NUMBER VARCHAR(20) NOT NULL,
HIRE_DATE DATE NOT NULL,
JOB_ID NUMBER NOT NULL,
SALARY DECIMAL NOT NULL,
DEPARTMENT_ID NUMBER NOT NULL,
CONSTRAINT emp_job_fk FOREIGN KEY(JOB_ID) REFERENCES JOBS(JOB_ID),
CONSTRAINT emp_department_fk FOREIGN KEY(DEPARTMENT_ID) REFERENCES DEPARTMENT(DEPARTMENT_ID)
);
INSERT INTO DEPARTMENT (DEPARTMENT_ID,DEPARTMENT_NAME)
VALUES(1,'IT');
INSERT INTO DEPARTMENT (DEPARTMENT_ID,DEPARTMENT_NAME)
VALUES(2,'Sales');
INSERT INTO JOBS (JOB_ID,JOB_TITLE,MIN_SALARY,MAX_SALARY)
VALUES (1,'IT Administrator',250000.00,50000.00);
INSERT INTO JOBS (JOB_ID,JOB_TITLE,MIN_SALARY,MAX_SALARY)
VALUES (2,'Salesman',200000.00,40000.00);
Here is I create so far but it give me a error
ORA-00979: not a GROUP BY expression
00979. 00000 - "not a GROUP BY expression"
*Cause:
*Action:
Error at Line: 4 Column: 9
Here is my code
select department_id,department_name,total_salary
from(
select department_id,department_name, SALARY, count(*) as total_salary from(
select dep.department_id , dep.department_name ,emp.SALARY,
DENSE_RANK() OVER (PARTITION BY department_name ORDER BY salary)
from departments dep
inner join employees emp on dep.DEPARTMENT_ID = emp.DEPARTMENT_ID
)
GROUP BY SALARY)
Your query needs to join EMPLOYEES (to get the salaries) to DEPARTMENT (to get the DEPARTMENT_NAME). Calculate the total salary for each department by summing the employee salaries, not counting them. The GROUP BY needs to include the non-aggregated columns.
Then you need to rank the departments by the total salary per department. This query ranks the departments with highest salary = 1. It uses a left join to cater for departments with no employees.
select department_id
, department_name
, total_salary
, rank() over (order by total_salary desc) as dept_rank
from (
select d.department_id
, d.department_name
, sum(e.SALARY) as total_salary
from department d
left join employees e
on e.department_id = d.department_id
group by d.department_id
, d.department_name
)
/

Problems using GROUP BY and ORDER BY in SQL Oracle

So I've been instructed to write a SQL query to display the manager number and the salary of the lowest paid employee for that manager(2 columns within a database I'm working in). I must also exclude any groups where the minimum
salary is less than or equal to $6,000. Sort the output in descending order of
salary. Now I've successfully displayed the data however, I cannot seem to order it in descending order which is what brought me here. Currently my code is as follows:
Code Snippet #1
SELECT manager_id AS "Manager ID",
MIN(salary) AS "Lowest Paid Salary"
FROM employees
WHERE manager_id IS NOT NULL
AND salary > 6000
GROUP BY manager_id;
Which gives me the following output:
Code Snippet #2
Manager ID Lowest Paid Salary
---------- ------------------
100 6500
147 6200
205 8300
108 6900
148 6100
149 6200
102 9000
101 6500
145 7000
146 7000
However, I need these values ordered from Largest -> Smallest salary. I attempted to add a GROUP BY salary DESC; At the end of the statement which would give me the following error: ORA-00979: not a GROUP BY expression
Upon some research I found that the two (GROUP BY and ORDER BY) cannot be used together in the same query as I did not include both manager_id and salary within the GROUP BY clause. So I attempted that with the following code:
SELECT manager_id AS "Manager ID",
MIN(salary) AS "Lowest Paid Salary"
FROM employees
WHERE manager_id IS NOT NULL
AND salary > 6000
GROUP BY manager_id, salary
ORDER BY salary DESC;
Which gives me a list of all the salaries for each manager_id as well as duplicates. This is not what I am looking for.
I apologize for the excess of reading, I just want to make sure you know what I've tried and what I am attempting to accomplish.
So I need to know a way I can either use both the GROUP BY and ORDER BY in the same query to display the Code snippet #2 but have it ordered. Or another way to order this data in the same format.
Thanks in advance for any help/advice.
You can either sort by the column number or column name
SELECT manager_id AS "Manager ID",
MIN(salary) AS "Lowest Paid Salary"
FROM #employees
WHERE manager_id IS NOT NULL
AND salary > 6000
GROUP BY manager_id
order by 2 desc
SELECT manager_id AS "Manager ID",
MIN(salary) AS "Lowest Paid Salary"
FROM #employees
WHERE manager_id IS NOT NULL
AND salary > 6000
GROUP BY manager_id
order by "Lowest Paid Salary" desc
You need to order by the aggregate function. ...
Try this
SELECT manager_id AS "Manager ID",
MIN(salary) AS "Lowest Paid Salary"
FROM employees
WHERE manager_id IS NOT NULL
AND salary > 6000
GROUP BY manager_id
ORDER BY min(salary) DESC;
Try:
order by manager_id ,salary DESC and remove the group by clause
for example
SELECT * FROM Customers
ORDER BY CustomerID DESC,CustomerName;
This statement will arrange the results according to customer id in desc order.

Difference between not exists and not in

Please somebody explain why
select count(*) from employees where employee_id not in (select manager_id from employees)
returns 0
when clearly there are some employees who are managers also.
I am using HR schema.
based on the query i would suggest you to use
NOT EXISTS as it gives BOOLEAN result which boosts up the performance.
SELECT COUNT(*)
FROM employees
WHERE NOT EXISTS
(SELECT employee_id
FROM employees
WHERE type = 'manager' -- or however you differentiate
-- employees and managers
);
Based on this it looks like you're trying to link the employee_id with the manager_id, which are probably different.
Instead you could query for matching employee_id values for managers, using some other criteria to identify managers in the employees table.
SELECT COUNT(*)
FROM employees
WHERE employee_id NOT IN
(
SELECT employee_id
FROM employees
WHERE type = 'manager' -- or however you differentiate
-- employees and managers
)

Resources