【问题标题】:I have written the code for a PLSQL exception handler, but still it's not passing the test case in HackerRank我已经为 PLSQL 异常处理程序编写了代码,但它仍然没有通过 HackerRank 中的测试用例
【发布时间】:2021-12-26 10:52:47
【问题描述】:

编写一个 PLSQL 块来获取分配给 EMP 表中员工的不同部门 ID。部门详细信息,例如部门名称和所有需要从部门表中检索。此处不遵循 SQL 完整性约束,因此您可能会发现 DEPT 表中不可用的记录。确保处理所有必需的异常以处理这些记录。

架构详细信息是:

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

我已经编写了代码,但每次运行时,输出都与问题中的要求相似,但未通过测试用例。

Question screenshot

Test Case error message

我的代码:

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;

【问题讨论】:

  • 你不需要这个循环(包含另一个SELECT)。可以调整光标以仅返回 EXISTSemp.dept_id 中的那些 dept_id 值。使用WHERE EXISTS (...)时不需要DISTINCT
  • 您的问题不包括测试要求的一些细节。您可以使用OUTER JOIN 来检测缺失的案例。
  • 答案更新了错误的程序和更正的程序。我没有替换您额外的 SELECT 语句。我只是按原样使用它们,稍作调整以从光标引用新的isexists 派生列。
  • 也许程序没有问题,看起来还不错。问题可能是您的结果没有足够的信息。 IE。你没有达到要求。要求清楚地说明了部门详细信息,例如部门名称和所有需要检索的内容。这似乎是说输出必须有 DEPT_HEAD、DEPT_ID、DEPT_NAME。你试过吗?

标签: sql oracle exception plsql plsqldeveloper


【解决方案1】:

问题是:

编写一个 PL/SQL 块来获取分配给 EMP 表中员工的不同部门 ID。

您只需从EMP 表中获取DEPT_ID 值并检查它们是否有效(即它们存在于DEPT 表中);您不需要在DEPT 表中打印EMP 表中不存在的任何ID,因此使用FULL OUTER JOIN 是错误的。


在光标中使用LEFT OUTER JOIN

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;
/

另外,请注意格式化输出,使其与预期输出匹配。

其中,对于样本数据:

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;

输出:

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小提琴here

【讨论】:

    【解决方案2】:

    使用您的 SQL 测试用例以显示结果缺少行:

    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;
    /
    

    结果:

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

    请注意,此结果中缺少 dept_id = 3。

    这就是为什么您需要像 FULL JOIN 这样的东西来检测两种缺失的类型,dept_id 不包含在 empdept_id 中的 emp 中不存在 dept

    现在更正的程序:

    我没有删除不必要的SELECT INTO 语句。这些并不是真正需要的,因为光标包含您需要的所有内容。

    -- 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;
    /
    

    正确结果:

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

    通知dept_id = 3 在结果中。

    如果我们想要保证dept_id order 中的 order,我们可以在游标查询中添加以下内容:

    ORDER BY COALESCE(dept.dept_id, isExists)
    

    带有描述的原始答案:

    您的尝试未检测到存在与emp 行无关的dept.dept_id 的情况。您的 SQL 仅查找 emp 表引用的 dept_id。

    光标只需:

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

    这会根据要求提供所有部门详细信息的不同列表,以及指示是否找到相应部门的员工记录的列。

    emp 行引用无效的dept_id 时,dept.dept_id 将为空,结果中的isExists 列包含缺少的dept_id

    FULL JOIN 检测到不在dept 表中的emp.dept_id 和不在emp 表中的dept.dept_id

    测试用例:

    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
    ;
    

    结果:

    DEPT_ID ISEXISTS
    1 1
    null 2
    3 null

    【讨论】:

    • 我尝试运行建议的 SELECT 但它没有清除 Hackerrank 中的测试用例。 SELECT 语句要求一个 INTO 子句。 :(
    • @AbhijitBiswas 更正。您的 SQL 仅在 emp 中找到无效的 dept_id,而不是在 emp 表中找不到的那些 dept_id。
    • @AbhijitBiswas 您的逻辑在我的示例中找不到第三种情况,因为没有包含dept_id = 3emp 行。您只是在 emp 表中搜索 dept_id 的列表。
    • @AbhijitBiswas 顺便说一句,我只提供了游标查询,没有提供任何 SELECT ... INTO ... 逻辑。游标应支持您需要的任何SELECT ... INTO ...,以及指示emp 行是否与给定dept_id 匹配的额外列。
    • @AbhijitBiswas 在您发布的测试问题中没有任何地方提到SELECT INTO。没有必要这样做。只需直接引用游标,根据需要检查是否为空,以检测发现了哪些异常情况。不需要异常处理程序。空值提供了详细信息。
    猜你喜欢
    • 1970-01-01
    • 2021-12-13
    • 2018-06-02
    • 1970-01-01
    • 2020-11-28
    • 2013-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多