PL / pgSQL中奇怪的日期差异问题

时间:2011-10-16 10:46:04

标签: postgresql plpgsql

我已经写了一个程序,应该根据每个人的经验日来增加员工表的工资。增加的值在另一个表中。有人能告诉我为什么它不会增加工作超过3650天的员工的薪水吗?

DECLARE
   row record;
   row2 record;
   dateDiff int;

BEGIN
  FOR row IN EXECUTE 'SELECT * FROM employee'
  LOOP
     FOR row2 IN SELECT * FROM increases
     LOOP
        dateDiff := now()::date - row.empjoindate;
        IF dateDiff> 3650 THEN
           RAISE NOTICE '%', dateDiff;
        END IF;
        IF dateDiff >= row2.employment_length_from
       AND dateDiff <  row2.employment_length_to THEN 
           UPDATE employee SET empsalary = empsalary + row2.pay_rise WHERE empid = row.empid;
        END IF;
     END LOOP;
  END LOOP;
END;

增加工资的表格如下:

 id | employment_length_from | employment_length_to | pay_rise
----+------------------------+----------------------+----------
  2 |                   3650 |                 7300 |      200
  3 |                   7300 |                10950 |      400
  4 |                  10950 |                14600 |      600
  5 |                  14600 |                18250 |      800
  6 |                  18250 |                21900 |     1000
  1 |                      0 |                 3650 |      100

如果问题不明确,请问我问题。

修改

表定义是: 对于员工:

     Column      |            Type             | Modifiers
-----------------+-----------------------------+-----------
 empid           | integer                     | not null
 empemailaddress | character varying(255)      | not null
 empjoindate     | date                        |
 emplastname     | character varying(255)      |
 emplogintime    | timestamp without time zone |
 empname         | character varying(255)      |
 ispermanent     | boolean                     | not null
 empsalary       | double precision            |

索引:

"employee_pkey" PRIMARY KEY, btree (empid)

增加:

         Column         |       Type       | Modifiers
------------------------+------------------+-----------
 id                     | integer          | not null
 employment_length_from | integer          |
 employment_length_to   | integer          |
 pay_rise               | double precision |

索引:

"increases_pkey" PRIMARY KEY, btree (id)

2 个答案:

答案 0 :(得分:1)

DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp;

CREATE TABLE tmp.increases
    (id INTEGER NOT NULL PRIMARY KEY
    , employment_length_from INTEGER NOT NULL
    , employment_length_to INTEGER NOT NULL
    , pay_rise double precision
    );
INSERT INTO tmp.increases(id
             ,employment_length_from,employment_length_to,pay_rise)
VALUES
    (1 , 0 , 3650 , 100)
    ,(2 , 3650 , 7300 , 200)
    ,(3 , 7300 , 10950 , 400)
    ,(4 , 10950 , 14600 , 600)
    ,(5 , 14600 , 18250 , 800)
    ,(6 , 18250 , 21900 , 1000)
    ;

CREATE TABLE tmp.employee
    ( empid INTEGER NOT NULL
    , empemailaddress VARCHAR (255) not null
    , empjoindate DATE
    , emplastname VARCHAR (255)
    , emplogintime TIMESTAMP WITHOUT TIME ZONE
    , empname VARCHAR(255)
    , ispermanent BOOLEAN NOT NULL
    , empsalary DOUBLE PRECISION
    );
INSERT INTO tmp.employee(empid,empemailaddress,empjoindate,emplastname,emplogintime,empname,ispermanent,empsalary)
VALUES
(1,'lutser@nocorp.com' , '1939-01-01', 'Lutser', '2011-09-30' , 'Kleine' , True, 100.0 )
, (2,'lutser@nocorp.com' , '1949-01-01', 'Prutser', '2011-10-01' , 'Grote' , True, 200.0 )
, (3,'lutser@nocorp.com' , '1959-01-01', 'Klutser', '2011-10-01' , 'Grote' , True, 200.0 )
, (4,'lutser@nocorp.com' , '1969-01-01', 'Glutser', '2011-10-01' , 'Grote' , True, 200.0 )
, (5,'lutser@nocorp.com' , '1979-01-01', 'Brutser', '2011-10-01' , 'Grote' , True, 200.0 )
, (6,'lutser@nocorp.com' , '1989-01-01', 'Mutser', '2011-10-01' , 'Grote' , True, 200.0 )
    ;

SELECT * FROM tmp.employee ;

-- EXPLAIN ANALYZE
UPDATE tmp.employee emp
SET empsalary = empsalary + inc.pay_rise
FROM tmp.increases inc
    WHERE (now() - emp.empjoindate)
          >= inc.employment_length_from * '1 day'::interval
    AND (now() - emp.empjoindate)
         < inc.employment_length_to * '1 day'::interval
    ;
SELECT * FROM tmp.employee ;

间隔和整数之间的转换可能很痛苦。上面我通过将int乘以1天的间隔来解决这个问题。现在,您可以将此片段嵌入过程/函数中。

答案 1 :(得分:0)

一个简单的UPDATE应该:

UPDATE employee e
SET    empsalary = empsalary + i.pay_rise
FROM   increases i
WHERE  (now()::date - e.empjoindate) >= i.employment_length_from
AND    (now()::date - e.empjoindate)  < i.employment_length_to;

你不需要plpgsql函数。
我会建议你在他们加注时标记行(在同一个查询中),这样你就不会意外地多次加注。

编辑:

这是一个plpgsql函数,就像你要求的那样。它返回获得加薪的员工数量。

CREATE OR REPLACE FUNCTION f_raise(OUT happy_employees integer) AS
$BODY$
BEGIN

UPDATE employee e
SET    empsalary = empsalary + i.pay_rise
FROM   increases i
WHERE  (now()::date - e.empjoindate) >= i.employment_length_from
AND    (now()::date - e.empjoindate)  < i.employment_length_to;

GET DIAGNOSTICS happy_employees = ROW_COUNT;

END;
$BODY$
  LANGUAGE plpgsql VOLATILE;
COMMENT ON FUNCTION f_raise() IS 'Gives employees who deserve it a raise.
Returns number of happy employees.'