Hackerrank Question PLSQL Employees not assigned to any department - oracle

Has someone completed the hackerrank PLSQL for the practice "Employees not assigned to any department"? Hackerrank can be a little tricky with the output and I am really stuck on this one. Can you please give a look at the code and let me know if I am missing anything?
The problem is as follows:
Write a PLSQL block which should assign department_id and department_manager to the Active employees who does not belong to any department. Department which you assign to the Active employees should not have any employees tagged to it. (Please check the attached image for the Schema tables and the Output format)
This is the code I have:
SET SERVEROUTPUT ON;
DECLARE
DEPTID DEPT.DEPT_ID%TYPE;
MGRID EMP.MGR_ID%TYPE;
BEGIN
SELECT DEPT_ID, DEPT_HEAD
INTO DEPTID, MGRID
FROM DEPT D
WHERE DEPT_ID NOT IN (SELECT DEPT_ID FROM EMP E WHERE D.DEPT_ID= E.DEPT_ID);
UPDATE EMP E
SET DEPT_ID = DEPTID, MGR_ID= MGRID
WHERE DEPT_ID IS NULL
AND EMP_STATUS='Active';
DECLARE
CURSOR C IS
SELECT E.EMP_ID, E.EMP_FNAME, E.EMP_LNAME, E.EMP_STATUS, D.DEPT_NAME, T2.EMP_FNAME MNG_FNAME, T2.EMP_LNAME MNG_LNAME
FROM EMP E
INNER JOIN DEPT D ON D.DEPT_ID=E.DEPT_ID
INNER JOIN EMP T2 ON E.MGR_ID = T2.EMP_ID
WHERE E.EMP_STATUS='Active'
AND E.DEPT_ID=DEPTID;
BEGIN
DBMS_OUTPUT.PUT_LINE('emp_Id'||'emp_fname'||'emp_Lname'||'emp_Status'||'Dept_name'||'Mgr_name');
FOR I IN C LOOP
DBMS_OUTPUT.PUT_LINE(i.emp_id||''||i.emp_fname||''||i.emp_lname||''||i.emp_status||''||i.dept_name||''||concat(i.mng_fname||'',i.mng_lname));
END LOOP;
END;
END;
/

Related

I have data with formulas and User expecting calculation of data dynamically

I attached my sample data and in summary expected calculation dynamically.
For example: Table 1, Table 2 is the source data and Lookup table (Business_rule) had calculation rule under calculation_rule. so using Table 1, Table 2 data user expected apply calculation_rule and want to get result as per in Output table. Source table are in Oracle Database.
I tried with all algorithms like xmltable etc. but not working.
Here table 1 = employees; table 2 = departments; output is dbms_output.
DECLARE
v_sql VARCHAR2(1000);
lc_cur SYS_REFCURSOR;
ln_employee_id VARCHAR2(10);
ln_department_id NUMBER;
ln_calc_amt NUMBER;
BEGIN
FOR rec IN (SELECT e.department_id, br.metric_code
FROM employees e INNER JOIN business_rule br on e.department_id = br.department_id
)
LOOP
SELECT 'SELECT e.employee_id, d.department_id,'||calculation_rule||'
from employees e inner join departments d on e.department_id = d.department_id
where e.department_id = '||rec.department_id
INTO v_sql
FROM business_rule WHERE department_id = rec.department_id;
OPEN lc_cur FOR v_sql;
LOOP
FETCH lc_cur INTO ln_employee_id, ln_department_id, ln_calc_amt;
EXIT WHEN lc_cur%NOTFOUND;
dbms_output.put_line(ln_employee_id||' - '||ln_department_id||' - '||rec.metric_code||' - '||ln_calc_amt);
END LOOP;
CLOSE lc_cur;
END LOOP;
END;

picking 1 column from 2 tables and comparing them

In my Oracle database there are two tables which are TEMP_HR and PAY_SLIP_APR_16. Both of them have a common column named EMP_ID. TEMP_HR has over 10,000 records and PAY_SLIP_APR_16 has around 6,000 records. I want to know how many EMP_ID of PAY_SLIP_APR_16 is matched with TEMP_HR. If any ID doesn't match then print it. And here is my simple approach but I think its a very bad approach. So any faster method?
DECLARE
INPUT_EMP_NO VARCHAR2(13 BYTE);
INPUT_EMP_ID VARCHAR2(13 BYTE);
ROW_COUNT_1 NUMBER(6,0);
ROW_COUNT_2 NUMBER(6,0);
MATCHED_ID NUMBER;
UNMATCHED_ID NUMBER;
BEGIN
ROW_COUNT_1:=0;
ROW_COUNT_2:=0;
MATCHED_ID:=0;
UNMATCHED_ID:=0;
SELECT COUNT(*) INTO ROW_COUNT_1 FROM PAY_SLIP_APR_16;
SELECT COUNT(*) INTO ROW_COUNT_2 FROM TEMP_HR;
FOR A IN 1..ROW_COUNT_1 LOOP
BEGIN
SELECT EMP_ID INTO INPUT_EMP_ID FROM (SELECT EMP_ID, ROWNUM AS RN FROM PAY_SLIP_APR_16) WHERE RN=A;
FOR B IN 1..ROW_COUNT_2 LOOP
SELECT EMP_NO INTO INPUT_EMP_NO FROM (SELECT EMP_NO, ROWNUM AS RON FROM TEMP_HR) WHERE RON=B;
IF(INPUT_EMP_ID=INPUT_EMP_NO)THEN
MATCHED_ID:=MATCHED_ID+1;
EXIT;
ELSE
CONTINUE;
END IF;
END LOOP;
UNMATCHED_ID:=UNMATCHED_ID+1;
DBMS_OUTPUT.PUT_LINE(INPUT_EMP_ID);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(INPUT_EMP_ID||' -> '||SQLERRM);
END;
END LOOP;
DBMS_OUTPUT.PUT_LINE('MATCHED -> '||MATCHED_ID);
DBMS_OUTPUT.PUT_LINE('UNMATCHED -> '||UNMATCHED_ID);
END;
Use an outer join filtering for missed joins:
select p.*
from PAY_SLIP_APR_16 p
left join TEMP_HR t on t.EMP_ID = p.EMP_ID
where t.EMP_ID is null
An index on TEMP_HR(EMP_ID) will make this query fly.
You should use SQL sets!
To check which EMP_ID isn't in TEMP_HR you may try this:
select EMP_ID FROM PAY_SLIP_APR_16
where EMP_ID not in (select EMP_NO from TEMP_HR);
Then the other way around:
select EMP_NO FROM TEMP_HR
where EMP_NO not in (select EMP_ID from PAY_SLIP_APR_16);

PL\SQL Hot do I convert select value to bit flag?

I would like to have pl-sql like the following:
SELECT ID FROM some-table WHERE
(SELECT MAX(some-expression) FROM another-table = 1) OR
(some-table.ID IN SELECT (SELECT ID FROM one-more-table))
This pseudo-query would select all IDs from some-table if maximum value of some-expression equals 1 (or filter IDs by one-more-table values otherwise)
How do I properly implement this in PL-SQL ?
Thank you in advance!
Please find the below pl-sql:
DECLARE
v_Column1 NUMBER(4);
v_deptno NUMBER(2);
BEGIN
SELECT MAX(A.DEPTNO)
INTO v_deptno
FROM (SELECT DEPTNO FROM DEPT) A;
SELECT A.EMPNO
INTO v_Column1
FROM EMP A
WHERE A.DEPTNO=v_deptno
OR
A.EMPNO IN ( SELECT EMPNO FROM EMP_2);
END;
/

Oracle pivoting unknown number of column before execution time

I have something like this:
id cod
1 a
1 b
1 c
2 d
2 e
3 f
3 g
and i need something like this:
id cod 1 cod 2 cod 3
1 a b c
2 d e
3 f g
you understand that there is no way to know how many column oracle will have to generate before the execution time.
You can use procedure p_pivot, code below. It dynamically builds view v_test based on your table.
Then you can select from this view like here:
Connected to Oracle Database 10g Release 10.2.0.4.0
SQL> execute p_pivot;
PL/SQL procedure successfully completed
SQL> select * from v_test;
ID COD1 COD2 COD3
---------- ----- ----- -----
1 a b c
2 d e
3 f g
Procedure (please change table name from test to your table name in code):
create or replace procedure p_pivot is
v_cols number;
v_sql varchar2(4000);
begin
select max(cnt) into v_cols
from (select count(1) cnt from test group by id);
v_sql :=
'create or replace view v_test as
with t as (select row_number() over (partition by id order by cod) rn, test.* from test)
select id';
for i in 1..v_cols
loop
v_sql := v_sql || ', max(decode(rn, '||i||', cod)) cod'||i;
end loop;
v_sql := v_sql || ' from t group by id';
execute immediate v_sql;
end p_pivot;
There is NO way how to do that. Oracle HAS to know the number of columns at the moment when it is compiling the query.
Imagine that you create a view using such a query. The view would have different number of columns each time you look at it.
Also there should be no way how to fetch data from such a query. Because you do not know how many columns have until you evaluate all the data in the table.
Hi You can use this query also.
--Creating test data
create table test_me(id_num number,val varchar2(10));
insert all
into test_me
values(1,'a')
into test_me values (1,'b')
into test_me values (1,'c')
into test_me values (2,'d')
into test_me values (2,'e')
into test_me values (3,'f')
into test_me values (3,'g')
select 1 from dual;
select * from
(
select id_num,val,row_number() over (partition by id_num order by val) rn
from test_me )
pivot (max(val) for id_num in(1 as val_1,2 as val_2,3 as val_3));
The SQLFiddle demo is here
http://sqlfiddle.com/#!4/4206f/1

can plsql function return object

i have encountered a problem while writing the following code:
create or replace function getashish(dept varchar2) return emp3 as
emp5 emp3;
str varchar2(300);
begin
str := 'select e.last_name,l.city,e.salary from employees e join departments d
on e.department_id = d.department_id join locations l on d.location_id=l.location_id where
d.department_name = :dept';
execute immediate str bulk collect into emp5 using dept;
end;
emp 3 is table of an object as defined below:
create or replace type emp1 as object (lname varchar2(10),city varchar2(10),sal number(10));
create or replace type emp3 as table of emp1;
i am getting the following error while executing the function: SQL Error:
ORA-00932: inconsistent datatypes: expected - got -
thank you for your anticipated help and support.
try declaring emp5 as a datatype of emp1.
emp5 emp1 := emp1();
Please try the below, (added emp1() to your select query inside function and returned emp5)
CREATE OR REPLACE FUNCTION getashish(
dept VARCHAR2)
RETURN emp3
AS
emp5 emp3 := emp3();
str VARCHAR2(300);
BEGIN
str := 'select emp1(e.last_name,l.city,e.salary) from employees e join departments d
on e.department_id = d.department_id join locations l on d.location_id=l.location_id where
d.department_name = :dept';
EXECUTE immediate str bulk collect INTO emp5 USING dept;
RETURN emp5;
END;
/
and the caller block
SELECT * FROM TABLE( CAST(getashish('IT') AS emp3))
UNION
SELECT * FROM TABLE( CAST(getashish('FINANCE') AS emp3));
the function returns a Table, and hence cant be used in SELECT clause, since it is supposed to return one row only, if have to be used in SELECT. Hope you got the concept!
EDIT: Whatever I did!
create table employees
(last_name varchar2(10),salary number,department_id varchar2(10));
create table locations
(location_id varchar2(10),city varchar2(10));
drop table employees;
create table departments
(department_id varchar2(10),location_id varchar2(10),department_name varchar2(10));
insert into employees values ('ASHISH',6000000,'D1');
insert into employees values ('MAHESH',5000000,'D2');
insert into departments values('D1','L1','IT');
insert into departments values('D2','L2','FINANCE');
insert into locations values('L1','Gurgoan');
insert into locations values('L2','Chennai');
commit;
create or replace type emp1 as object (lname varchar2(10),city varchar2(10),sal number(10));
/
create or replace type emp3 as table of emp1;
/
CREATE OR REPLACE FUNCTION getashish(
dept VARCHAR2)
RETURN emp3
AS
emp5 emp3 := emp3();
str VARCHAR2(300);
BEGIN
str := 'select emp1(e.last_name,l.city,e.salary) from employees e join departments d
on e.department_id = d.department_id join locations l on d.location_id=l.location_id where
d.department_name = :dept';
EXECUTE immediate str bulk collect INTO emp5 USING dept;
RETURN emp5;
END;
/
SELECT * FROM TABLE( CAST(getashish('IT') AS emp3))
UNION
SELECT * FROM TABLE( CAST(getashish('FINANCE') AS emp3));
SQL> SELECT * FROM TABLE( CAST(getashish('IT') AS emp3))
2 UNION
3 SELECT * FROM TABLE( CAST(getashish('FINANCE') AS emp3));
LNAME CITY SAL
---------- ---------- ----------
ASHISH Gurgoan 6000000
MAHESH Chennai 5000000

Resources