Difference between not exists and not in - oracle

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
)

Related

Oracle SQL join query to find highest salary

So I have two tables salary and emp whose definition is shown as below
[
I am tring to create a query that Find the employee who draws the maximum salary and Display the employee details along with the nationality.
I created this query
select empcode,
max(basic) as "Highest Sal"
from salary
join emp on empcode;
Please help with this
Your query uses a simple aggregate max(basic) which would find the highest salary. Except you need to join to the EMP table to display other details. This means you can't use aggregation, because we need to GROUP BY the non-aggregated columns, which would make a nonsense of the query.
Fortunately we can solve the problem with an analytic function. The subquery selects all the relevant information and ranks each employee by salary, with a rank of 1 being the highest paid. We use rank() here because that will handle ties: two employees with the same basic will be in the same rank.
select empcode
, empname
, nationality
, "Highest Sal"
from (
select emp.empcode
, emp.empname
, emp.nationality
, salary.basic as "Highest Sal"
, rank() over (order by salary.basic desc ) as rnk
from salary join emp on emp.empcode = salary.empcode
)
where rnk = 1;
Find the employee who draws the maximum salary
An employee can have multiple salaries in your datamodel. An employee's (total) salary hence is the sum of these. You want to find the maximum salary per employee and show the employee(s) earning that much.
You can use MAX OVER to find the maximum sum:
select e.*, s.total_salary
from emp e
join
(
select
empcode,
sum(basic) as total_salary,
max(sum(basic)) over () as max_total_salary
from salary
) s on s.empcode = e.empcode and s.total_salary = s.max_total_salary
order by e.empcode;
Try this:
SELECT * FROM
(SELECT E.EmpCode, E.EmpName, E.DOB, E.DOJ, E.DeptCode, E.DesgCode, E.PhNo,
E.Qualification, E.Nationality, S.Basic, S.HRA, S.TA, S.UTA, S.OTRate
FROM EMP AS E JOIN SALARY AS S ON (E.EmpCode = S.EmpCode) order by S.Basic desc)
WHERE rownum = 1

Query taking long when i use user defined function with order by in oracle select

I have a function, which will get greatest of three dates from the table.
create or replace FUNCTION fn_max_date_val(
pi_user_id IN number)
RETURN DATE
IS
l_modified_dt DATE;
l_mod1_dt DATE;
l_mod2_dt DATE;
ret_user_id DATE;
BEGIN
SELECT MAX(last_modified_dt)
INTO l_modified_dt
FROM table1
WHERE id = pi_user_id;
-- this table contains a million records
SELECT nvl(MAX(last_modified_ts),sysdate-90)
INTO l_mod1_dt
FROM table2
WHERE table2_id=pi_user_id;
-- this table contains clob data, 800 000 records, the table 3 does not have user_id and has to fetched from table 2, as shown below
SELECT nvl(MAX(last_modified_dt),sysdate-90)
INTO l_mod2_dt
FROM table3
WHERE table2_id IN
(SELECT id FROM table2 WHERE table2_id=pi_user_id
);
execute immediate 'select greatest('''||l_modified_dt||''','''||l_mod1_dt||''','''||l_mod2_dt||''') from dual' into ret_user_id;
RETURN ret_user_id;
EXCEPTION
WHEN OTHERS THEN
return SYSDATE;
END;
this function works perfectly fine and executes within a second.
-- random user_id , just to test the functionality
SELECT fn_max_date_val(100) as max_date FROM DUAL
MAX_DATE
--------
27-02-14
For reference purpose i have used the table name as table1,table2 and table3 but my business case is similar to what i stated below.
I need to get the details of the table1 along with the highest modified date among the three tables.
I did something like this.
SELECT a.id,a.name,a.value,fn_max_date_val(id) as max_date
FROM table1 a where status_id ='Active';
The above query execute perfectly fine and got result in millisecods. But the problem came when i tried to use order by.
SELECT a.id,a.name,a.value,a.status_id,last_modified_dt,fn_max_date_val(id) as max_date
FROM table1 where status_id ='Active' a
order by status_id desc,last_modified_dt desc ;
-- It took almost 300 seconds to complete
I tried using index also all the values of the status_id and last_modified, but no luck. Can this be done in a right way?
How about if your query is like this?
select a.*, fn_max_date_val(id) as max_date
from
(SELECT a.id,a.name,a.value,a.status_id,last_modified_dt
FROM table1 where status_id ='Active' a
order by status_id desc,last_modified_dt desc) a;
What if you don't use the function and do something like this:
SELECT a.id,a.name,a.value,a.status_id,last_modified_dt x.max_date
FROM table1 a
(
select max(max_date) as max_date
from (
SELECT MAX(last_modified_dt) as max_date
FROM table1 t1
WHERE t1.id = a.id
union
SELECT nvl(MAX(last_modified_ts),sysdate-90) as max_date
FROM table2 t2
WHERE t2.table2_id=a.id
...
) y
) x
where a.status_id ='Active'
order by status_id desc,last_modified_dt desc;
Syntax might contain errors, but something like that + the third table in the derived table too.

Counting the Maximum Number of Values

I have a data table Employees, I want to show all the employees who have been hired on the same day on which the maximum number of employees has been hired. Here's my code:
select last_name, hire_date, count(*) as "Number of Employees Hired"
from employees
group by last_name, hire_date
where hire_date = max(count(*));
However, this code shows "SQL Command Not Properly Ended" error when I run it. How do I fix it so that it runs correctly?
This may not be the cleanest way, but I think will do the trick:
SELECT last_name,
max_hire.hire_date,
max_hire.cnt
FROM
(SELECT *
FROM
(SELECT hire_date,
COUNT(*) cnt
FROM employees
GROUP BY hire_date
ORDER BY COUNT(*) DESC
)
WHERE rownum = 1
) max_hire
INNER JOIN employees
ON employees.hire_date = max_hire.hire_date
Firstly, you should use WHERE before the GROUP BY clause and secondly you should use the aggregate function (count) correctly, as in your case count(*) cannot be compared within the WHERE clause.
You can go with the approach below without using where: (Tested under MySQL)
select last_name, hire_date, count(*) as "Number of Employees Hired"
from employees
group by last_name, hire_date
Order by "Number of Employees Hired" desc limit 1
Hope this helps. Cheers.

How to check if a person exsist and then insert into another table using pl/sql?

Create an anonymous PL/SQL block, which looks for an employee by last name based on a SQL parameter (e.g. &variable) that the user responds to with a valid last_name in the EMPLOYEES table (i.e. King, or Kochhar, or De Haan, or Hunold, or Ernst, etc….…). If the employee last_name exists in the EMPLOYEES table, then insert into the OUTPUT_LOG table, the following string:
'Employee is is Found'. Test your PL/SQL block by checking the content of the OUTPUT_LOG table. You should find the string the you inserted in the OUTPUT_LOG table.
employee table has these columns
EMPLOYEE_ID ,
FIRST_NAME ,
LAST_NAME ,
EMAIL ,
PHONE_NUMBER ,
HIRE_DATE ,
JOB_ID ,
SALARY ,
COMMISSION_PCT ,
MANAGER_ID ,
DEPARTMENT_ID
output_log table only has one column VARCHAR2(250) called data and id column as PRIMARY KEY
I am struggling to figure check if the name exist in the table. I thought about using
begin
SELECT e.LAST_NAME as LAST_NAME, o.data
INTO OUTPUT_LOG
FROM EMPLOYEES as e, OUTPUT_LOG as O
WHERE e.employee_id = o.id
end;
but i dont think it would be wise and make sense to do so
Since this appears to be a homework question, I'm not going to solve it all for you but (to help you on your way) you could just use SELECT ... INTO and if a row is not found it will raise a NO_DATA_FOUND exception which you can catch (and use this to bypass the INSERT). Something like this:
DECLARE
p_found NUMBER(1,0);
BEGIN
SELECT 1
INTO p_found
FROM Employees
WHERE ROWNUM = 1
AND last_name = 'King'; -- replace with your where condition
-- then do the insert here (since it will only reach this point if
-- a row was found).
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
END;
/

ORACLE: How to select previous different value?

I have table that stores employee job name, it has the following columns:
id; date_from; date_to; emp_id; jobname_id; grade;
Each emp_id can have many consecutive records with the same jobname_id due to many grade changes.
How can I select previous different jobname_id omitting those that are the same like the most current one?
This solution uses the FIRST_VALUE() analytic function to identify each employee's current job. It then filters for all the jobs which dfon't match that one:
select distinct id
, jobname_id
from ( select id
, jobname_id
, first_value(jobname_id) over (partition by id
order by from_date desc) as current_job
from employee
where emp_id = 1234 )
where jobname_id != current_job
order by id, jobname_id
/
Will this work for your issue:
SELECT DISTINCT
e1.emp_id,
e1.jobname_id
FROM employee e1
WHERE NOT EXISTS
(SELECT 1
FROM employee e2
WHERE e1.emp_id = e2.emp_id
AND SYSDATE BETWEEN e2.date_from
AND NVL(e2.date_to, SYSDATE + 1));
(This asumes your table is named "employee" and emp_id is the PK value).
It selects unique emp_id, jobname_id values where the emp_id, jobname_id values are not current.
EDIT: I agree with Chin Boon that fundamentally this is a design issue and perhaps that should be addressed rather than working around the problem.

Resources