Home > OS >  I have written the code for a PLSQL exception handler, but still it's not passing the test case
I have written the code for a PLSQL exception handler, but still it's not passing the test case

Time:11-24

Write a PLSQL block to fetch distinct department ids which is assigned to employees in EMP table. Department details such as dept name and all needs to be retrieved from DEPT Table. SQL integrity constraints are not followed here, and so you may find records which are not available in DEPT Tables. Make sure to handle all the required exceptions to take care of these records.

Schema details are:

TABLE NAME         COLUMN NAMES
------------       -------------------------------------------------
DEPT               DEPT_HEAD, DEPT_ID, DEPT_NAME

EMP                DEPT_ID, EMP_ACTIVEFROM, EMP_DOB, EMP_FNAME, EMP_ID, EMP_LNAME, 
                           EMP_SAL, EMP_STATUS, EMP_TERMINATIONDATE, LOC_ID, MGR_ID

I have written the code, but every time I run this, the output is coming similar to what is asked in the question but it's not passing the Test case.

Question screenshot

Test Case error message

My code:

SET SERVEROUTPUT ON
DECLARE
    l_dept_name dept.dept_name%type;
BEGIN
    for cur_r in(select distinct e.dept_id from EMP e)
    loop
        begin
            select d.dept_name into l_dept_name from DEPT d where d.dept_id = cur_r.dept_id;
            dbms_output.put_line('Dept ID: '|| cur_r.dept_id||' is '||l_dept_name);
        exception
            when NO_DATA_FOUND then
                dbms_output.put_line('Dept ID: '|| cur_r.dept_id ||' is not a valid ID');
        end;
    end loop;
END;
/
EXIT;

CodePudding user response:

Test case with your SQL to show the result is missing rows:

Fiddle with the procedure, and the corrected procedure

CREATE TABLE dept (dept_id int, dept_name varchar2(10));

CREATE TABLE emp  (dept_id int);

BEGIN
INSERT INTO dept VALUES (1, 'd1');
INSERT INTO dept VALUES (3, 'd3');
INSERT INTO emp VALUES (1);
INSERT INTO emp VALUES (2);
END;
/

SELECT dept.dept_id, dept.dept_name, emp.dept_id AS isExists
  FROM dept FULL JOIN emp ON dept.dept_id = emp.dept_id
;

-- The original procedure, with missing results:
DECLARE
    l_dept_name dept.dept_name%type;
BEGIN
    for cur_r in(select distinct e.dept_id from EMP e)
    loop
        begin
            select d.dept_name into l_dept_name from DEPT d where d.dept_id = cur_r.dept_id;
            dbms_output.put_line('Dept ID: '|| cur_r.dept_id||' is '||l_dept_name);
        exception
            when NO_DATA_FOUND then
                dbms_output.put_line('Dept ID: '|| cur_r.dept_id ||' is not a valid ID');
        end;
    end loop;
END;
/

The results:

dbms_output:
Dept ID: 2 is not a valid ID
Dept ID: 1 is d1

Notice dept_id = 3 is missing in this result.

That's why you need something like a FULL JOIN to detect both missing types, both dept_id not contained in emp and dept_id in emp that doesn't exist in dept.

Now the corrected procedure:

I didn't remove the unnecessary SELECT INTO statements. Those aren't really needed, since the cursor contains everything you need.

-- The new procedure, with all expected results:

DECLARE
    l_dept_name dept.dept_name%type;
BEGIN
    for cur_r in(
        SELECT DISTINCT dept.dept_id, dept.dept_name, emp.dept_id AS isExists
          FROM dept FULL JOIN emp ON dept.dept_id = emp.dept_id
        )
    loop
        begin
            select d.dept_name into l_dept_name from DEPT d where d.dept_id = cur_r.dept_id;
            dbms_output.put_line('Dept ID: '|| cur_r.dept_id||' is '||l_dept_name);
        exception
            when NO_DATA_FOUND then
                dbms_output.put_line('Dept ID: '|| cur_r.isexists ||' is not a valid ID');
        end;
    end loop;
END;
/

The correct result:

dbms_output:
Dept ID: 1 is d1
Dept ID: 2 is not a valid ID
Dept ID: 3 is d3

Notice dept_id = 3 is in the result.

If we want the order guaranteed in dept_id order, we can add the following to the cursor query:

ORDER BY COALESCE(dept.dept_id, isExists)

Original answer with description:

Your attempt doesn't detect the cases where a dept.dept_id exists which is not associated with an emp row. Your SQL only finds dept_id's which are referenced by the emp table.

The cursor only needs to be:

SELECT DISTINCT dept.*
     , emp.dept_id AS isExists
  FROM dept FULL JOIN emp ON dept.dept_id = emp.dept_id
;

This provides the distinct list of all dept detail, as requested, plus a column indicating if an employee record was found for the corresponding department.

When an emp row refers to an invalid dept_id, dept.dept_id will be null, and the isExists column in the result contains that missing dept_id.

FULL JOIN detects both emp.dept_id which is not in dept table and dept.dept_id which is not found in the emp table.

Test case:

Fiddle

WITH emp  (dept_id) AS (SELECT 1 FROM dual UNION SELECT 2 FROM dual)
   , dept (dept_id) AS (SELECT 1 FROM dual UNION SELECT 3 FROM dual)
SELECT dept.dept_id, emp.dept_id AS isExists
  FROM dept FULL JOIN emp ON dept.dept_id = emp.dept_id
;

Result:

DEPT_ID ISEXISTS
1 1
null 2
3 null

CodePudding user response:

The question is:

Write a PL/SQL block to fetch the distinct department ids which is assigned to employees in the EMP table.

You only need to fetch the DEPT_ID values from the EMP table and check if they are valid (i.e. they exist in the DEPT table); you do not need to print any ids in the DEPT table that do not exist in the EMP table so using a FULL OUTER JOIN is wrong.


Use a LEFT OUTER JOIN in the cursor:

SET SERVEROUTPUT ON;

BEGIN
  FOR r IN (SELECT DISTINCT
                   e.dept_id,
                   d.dept_name
            FROM   EMP e
                   LEFT OUTER JOIN DEPT d
                   ON e.dept_id = d.dept_id)
  LOOP
    IF r.dept_name IS NULL THEN
      DBMS_OUTPUT.PUT_LINE( 'Dept_ID :'||r.dept_id|| ' is not a valid ID');
    ELSE
      DBMS_OUTPUT.PUT_LINE( 'Dept_ID :'||r.dept_id|| ' is '||r.dept_name);
    END IF;
  END LOOP;
END;
/

Also, take care that you format the output so that it matches the expected output.

Which, for the sample data:

CREATE TABLE dept (dept_id, dept_name) AS
SELECT 1, 'Dept_name1' FROM DUAL UNION ALL
SELECT 2, 'Dept_name2' FROM DUAL UNION ALL
SELECT 4, 'Dept_name4' FROM DUAL;

CREATE TABLE emp (emp_id, dept_id) AS
SELECT 1, 1 FROM DUAL UNION ALL
SELECT 2, 1 FROM DUAL UNION ALL
SELECT 3, 3 FROM DUAL UNION ALL
SELECT 4, 4 FROM DUAL UNION ALL
SELECT 5, 5 FROM DUAL UNION ALL
SELECT 6, 5 FROM DUAL;

Outputs:

Dept_ID :1 is Dept_name1
Dept_ID :4 is Dept_name4
Dept_ID :3 is not a valid ID
Dept_ID :5 is not a valid ID

db<>fiddle here

  • Related