PL / SQL时间和半个游标

时间:2015-11-19 11:44:51

标签: oracle plsql

**问题是:如果他们加班,计算小时工资。您应该使用40小时的基础并支付一半的时间。我现在的代码只需按小时工资计算小时数,我现在需要将工资与按小时工资分开前40小时。然后剩下的时间乘以每小时付费时间1.5,这只有两个人idno 2222和7777. **

我的代码是:

SET SERVEROUTPUT ON
DECLARE
  v_idno      paydata4.idno%TYPE;
  v_name      paydata4.name%TYPE;
  v_sal       paydata4.salary%TYPE;
  v_job       paydata4.jobcode%TYPE;
  v_pay       paydata4.payhr%TYPE;
  v_idno1     paytran1.idno%TYPE;
  v_hourswk   paytran1.hourswk%TYPE; 
  v_hours     allinfo1.hours%TYPE; 
  v_nothing number(4);
  CURSOR paydata4_cursor IS
     SELECT idno, name, salary, jobcode, payhr FROM paydata4
     ORDER BY idno;
CURSOR paytran1_cursor IS
     SELECT idno, hourswk FROM paytran1
     WHERE v_idno = idno
     order by idno;
    BEGIN
     OPEN paydata4_cursor;
     LOOP
     FETCH paydata4_cursor INTO v_idno, v_name, v_sal, v_job, v_pay;
     EXIT WHEN paydata4_cursor%NOTFOUND;
       IF paytran1_cursor%ISOPEN THEN
        CLOSE paytran1_cursor;
       END IF;
IF v_job = 'S'THEN
        v_sal := v_sal / 52;
       End if; 
            OPEN paytran1_cursor;
     v_hours := 0;
      loop
      if v_hours <= 40 AND v_job = 'H' THEN
           v_sal := v_pay * v_hours;
            END IF;
     if v_hours > 40 AND v_job = 'H' THEN
           v_sal := v_pay * 40;
            END IF;
     if v_hours > 40 AND v_job = 'H' THEN
           v_pay := v_pay * 1.5;
            END IF;

       FETCH paytran1_cursor INTO v_idno1, v_hourswk;
         EXIT WHEN paytran1_cursor%NOTFOUND;
       v_hours := v_hours + v_hourswk;
      dbms_output.put_line('The current amount is: '||v_hours);
         END LOOP;
       INSERT into allinfo1 
          VALUES(v_idno, v_name, v_hours, v_job, v_sal, v_nothing);
      CLOSE paytran1_cursor;
     END LOOP;
     CLOSE paydata4_cursor;
END;
/
SET SERVEROUTPUT OFF

输出为:

   SQL> select *
  2  from allinfo1;

IDNO NAME                 HOURS JO        PAY      OTPAY
---- --------------- ---------- -- ---------- ----------
1111 Ann French              45 S        1442
2222 Robert Costa            61 H        2700
3333 Linda Ames              40 H        2000
4444 Scott Brooks            43 S        1500
5555 Susan Ash               40 S        1096
6666 James Smith             44 S        1058
7777 Mary Jones              45 H        1440
8888 John Morse              40 H        1560

参考表:

SQL> select *
  2  from paydata4;

IDNO NAME                      J     SALARY      PAYHR
---- ------------------------- - ---------- ----------
1111 Ann French                S      75000          0
2222 Robert Costa              H          0         45
3333 Linda Ames                H          0         50
4444 Scott Brooks              S      78000          0
5555 Susan Ash                 S      57000          0
6666 James Smith               S      55000          0
7777 Mary Jones                H          0         36
8888 John Morse                H          0         39

预期输出为:

SQL> select *
  2  from allinfo1;

IDNO NAME                 HOURS JO        PAY      
---- --------------- ---------- -- ---------- 
1111 Ann French              45 S        1442
2222 Robert Costa            61 H        3218
3333 Linda Ames              40 H        2000
4444 Scott Brooks            43 S        1500
5555 Susan Ash               40 S        1096
6666 James Smith             44 S        1058
7777 Mary Jones              45 H        1710
8888 John Morse              40 H        1560

3 个答案:

答案 0 :(得分:2)

不要过于复杂。你的计算只需要在40岁以上的所有时间增加额外的半薪吗?

所以,一旦你有了工资和工时,你只需

 v_sal :=  (v_pay * v_hours) + ((v_pay * 0.5) * GREATEST(0, v_hours - 40));

如果v_hours&lt; 40第二个条款将结束为v_pay * 0.5 * 0 = 0

答案 1 :(得分:1)

你真的需要PL / SQL块吗?所有这些工作只能通过以下一个语句来完成:

insert into allinfo1 (idno, name, hours, jo, pay)
select p1.idno, p1.name, p1.jobcode, p1.payhr, 
       -- here you calculate how much to pay
       case when jobcode = 'H' and p1.payhr > 40 then ...
            when jobcode = 'H' and p1.payhr < 40 then ...
            ...
       else ... end pay
  from paydata4 p1, paytran1 p2
 where p1.idno = p2.idno;

这不是您需要的确切代码,因为它很难理解,您的代码会做什么。但是如果你详细解释(表格,列和公式),我可以更正我的代码。

答案 2 :(得分:0)

我会尝试回答你的问题。

  

CAVEAT:我目前无权访问SQL会话,因此无法访问   测试语法等,您可能需要自己调试。答案   旨在为您指明正确的方向。另外,你的例子   有很多问题,比如你似乎插入了六个值   allinfo1但是当你从中选择*时,你只能获得五列   返回等

无论如何,试试这个作为起点。 为了提高效率,我已将您的游标转换为一个游标,并使用COUNT(hourswk),以防paytran1表可以为每个idno创建多个条目。 我使用了光标记录来保存结果,而不是为了管理而创建许多变量。

SET SERVEROUTPUT ON
DECLARE
  --
  v_hours allinfo1.hours%TYPE;
  v_sal   paydata4.salary%TYPE;
  --
  jobcode_exception EXCEPTION;
  --
  CURSOR pay_cursor 
  IS
     SELECT idno, 
            pd4.name, 
            pd4.salary, 
            pd4.jobcode, 
            pd4.payhr,
            SUM(pt1.hourswk) AS hours_worked
       FROM paydata4 pd4
       JOIN paytran1 pt1 USING (idno)
      GROUP BY idno, 
               pd4.name, 
               pd4.salary, 
               pd4.jobcode, 
               pd4.payhr
      ORDER BY idno;
  --
BEGIN
  -- Loop through pay_cursor
  FOR pay_rec IN pay_cursor
  LOOP
     -- Check job type
     CASE pay_rec.jobcode
       WHEN 'S'
       THEN
          -- Just divide salary by 52
          v_sal := v_sal / 52;
       WHEN 'H'
       THEN
          -- Calculate overtime
          IF pay_rec.hours_worked <= 40
          THEN
             -- Just pay standard rate
             v_sal := pay_rec.payhr * v_hours;
          ELSIF pay_rec.hours_worked > 40
          THEN
             -- Pay standard rate for first 40 hours
             v_sal := pay_rec.payhr * 40;
             -- Plus the overtime beyond 40 hours (overtime rate * hours over 40)
             v_sal := v_sal + ((pay_rec.payhr * 1.5) * (pay_rec.hours_worked - 40));
          END IF;
       ELSE
          -- Raise an error
          RAISE_APPLICATION_ERROR(-20001, 'Error: Unexpected job code "'||pay_rec.jobcode||'" for idno: '||pay_rec.idno);
     END;
     -- Insert the result into the allinfo1 table
     INSERT into allinfo1 VALUES(pay_rec.idno, pay_rec.name, pay_rec.hours_worked, pay_rec.jobcode, v_sal);
  END LOOP;
  -- Commit the inserts (remove if commit is hapeneing elsewhere)
  COMMIT;
EXCEPTION
  WHEN others
  THEN
     -- Rollback the inserts?
     ROLLBACK;
     -- Re-raise the error
     RAISE;
END;
/
SET SERVEROUTPUT OFF