重构没有游标PL / SQL的代码

时间:2015-04-09 11:13:40

标签: oracle plsql

如何在不使用CURSOR的情况下重构这些代码行? 我是PL / SQL的初学者。 任何帮助,将不胜感激。谢谢

DECLARE
  CURSOR c_emps IS
    SELECT employee_id
      FROM bonus;

  v_region HR.REGIONS.region_name%TYPE;
  v_salary hr.employees.salary%TYPE;

BEGIN
  FOR r_emps IN c_emps LOOP
    SELECT reg.region_name, emp.salary
      INTO v_region, v_salary
      FROM hr.employees   emp,
           hr.departments dep,
           hr.Locations   loc,
           hr.countries   cot,
           hr.regions     reg
     WHERE emp.department_id = dep.department_id AND
           dep.location_id = loc.location_id AND
           loc.country_id = cot.country_id AND
           cot.region_id = reg.region_id AND
           employee_id = r_emps.employee_id;

    IF v_region = 'Europe' THEN
      UPDATE bonus
         SET bonus = bonus + (v_salary * .01)
       WHERE employee_id = r_emps.employee_id;
    ELSE
      UPDATE bonus
         SET bonus = v_salary * .01
       WHERE employee_id = r_emps.employee_id;
    END IF;  
  END LOOP;

  COMMIT;
END;
/

2 个答案:

答案 0 :(得分:6)

CURSOR c_emps IS
    SELECT employee_id
      FROM bonus;

您无需显式声明CURSOR。您可以在 CURSOR FOR LOOP 本身中执行此操作:

FOR r_emps IN (SELECT employee_id FROM bonus) 
LOOP

如果 PL / SQL 不是必需的,那么您可以使用 UPDATE <中的 CASE表达式在纯 SQL 中执行此操作/ strong>声明。

类似的东西,

UPDATE bonus
SET bonus =
  CASE
    WHEN region = 'Europe'
    THEN bonus    + (v_salary * .01)
    ELSE v_salary * .01
...
and so on

是的,您需要将整个PL / SQL代码重写为SQL更新语句。但是,它会更好更快。 For循环是逐行处理,因此它是慢 - 慢。如果你可以在SQL中做同样的事情,请避免使用PL / SQL。

答案 1 :(得分:1)

使用SQL Server时,需要花费大量精力来避免使用游标,因为它们的处理非常糟糕。在SQL Server中使用光标就像在糖蜜中穿过腰部一样深。 Oracle更好地处理游标,因此您可以在Oracle中看到更多的逐行工作。实在太多了。即使在Oracle中,如果可以使用单个SQL语句完成某些操作,那么它远优于使用PL / SQL游标和循环。

不幸的是,Oracle不允许在UPDATE语句中加入。但不要担心,最新的创新,MERGE声明确实如此。

MERGE INTO BONUS B
USING(
    SELECT  EMP.EMPLOYEE_ID, EMP.SALARY, REG.REGION_NAME
    FROM    HR.EMPLOYEES   EMP
    JOIN    HR.DEPARTMENTS DEP
       ON   DEP.DEPARTMENT_ID = EMP.DEPARTMENT_ID
    JOIN    HR.LOCATIONS   LOC
       ON   LOC.LOCATION_ID = DEP.LOCATION_ID
    JOIN    HR.COUNTRIES   COT
       ON   COT.COUNTRY_ID = LOC.COUNTRY_ID
    JOIN    HR.REGIONS     REG
       ON   REG.REGION_ID = COT.REGION_ID ) U
ON( U.EMPLOYEE_ID = b.EMPLOYEE_ID )
WHEN MATCHED THEN
    UPDATE SET B.BONUS =( u.SALARY * 0.01 ) +
        CASE U.REGION_NAME WHEN 'Europe' THEN B.BONUS ELSE 0 END;

不需要when not matched子句,有效地将merge变为非常灵活的update