plpgsql函数:执行查询,处理记录和return原始结果集为table

plpgsql function: execute query, process records and return original result set as table

我想要一个执行以下操作的函数:执行查询,然后处理结果集中的所有数据记录,然后 returns 原始结果集。 所以我有这个 table:

 employee_state_id | employee_id | start_date |  end_date  | state |          created           |          modified
-------------------+-------------+------------+------------+-------+----------------------------+----------------------------
                29 |           1 | 2008-12-15 | 2008-12-31 | 1     | 2020-02-12 02:26:56.999502 | 2020-02-12 02:26:56.999502
                31 |           1 | 2009-01-01 | 2010-05-04 | 2     | 2020-02-12 02:27:42.973775 | 2020-02-12 02:27:42.973775
(2 rows)

有开始和结束日期的记录。如果此持续时间低于作为参数给出的值并且存在具有相同 ID 的后续记录,则合并这两个记录。最后,return 合并前记录的值。

select combine ('1', '2', 30);调用后,table中应该只有一个条目如下: (这已经适用于该功能)

 employee_state_id | employee_id | start_date |  end_date  | state |          created           |          modified
-------------------+-------------+------------+------------+-------+----------------------------+----------------------------
                32 |           1 | 2008-12-15 | 2010-05-04 | 2     | 2020-02-12 01:36:51.731834 | 2020-02-12 01:36:51.731834

但是 table 应该像这样把原始记录还给我:

 employee_id | a_employee_state_id | a_start_date  | a_end_date   | a_state | a_created                  | a_modified                 | b_employee_state_id | b_start_date  | b_end_date  | b_state | b_created                  | b_modified
-------------+---------------------+---------------+--------------+---------+----------------------------+----------------------------+---------------------+---------------+-------------+---------+----------------------------+---------------------------
           1 |                  29 |    2008-12-15 | 2008-12-31   |       1 | 2020-02-12 02:26:56.999502 | 2020-02-12 02:26:56.999502 |                  31 | 2009-01-01    | 2010-05-04  | 2       | 2020-02-12 02:27:42.973775 | 2020-02-12 02:27:42.973775

但这不起作用。我得到这样的东西:

postgres=# select combine('1', '2', 30);
                                                                                    combine
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 (1,29,2008-12-15,2008-12-31,1,"2020-02-12 02:26:56.999502","2020-02-12 02:26:56.999502",31,2009-01-01,2010-05-04,2,"2020-02-12 02:27:42.973775","2020-02-12 02:27:42.973775")
(1 row)

我尝试了以下功能,但它似乎不起作用。有谁知道如何(更优雅地)解决这个任务?

CREATE OR REPLACE FUNCTION combine(changeFrom text, changeTo text, afterDays int4)
  RETURNS TABLE (
  employee_id int4,
  a_employee_state_id int4,
  a_start_date date,
  a_end_date date,
  a_state text,
  a_created timestamp,
  a_modified timestamp,
  b_employee_state_id int4,
  b_start_date date,
  b_end_date date,
  b_state text,
  b_created timestamp,
  b_modified timestamp
)
  AS $$
DECLARE
    rec RECORD;
begin

  FOR rec in  
    SELECT -- this query works
      a1.employee_id,
      a1.employee_state_id AS a_employee_state_id,
      a1.start_date AS a_start_date,
      a1.end_date AS a_end_date,
      a1.state AS a_state,
      a1.created AS a_created,
      a1.modified AS a_modified,
      a2.employee_state_id AS b_employee_state_id,
      a2.start_date AS b_start_date,
      a2.end_date AS b_end_date,
      a2.state AS b_state,
      a2.created AS b_created,
      a2.modified AS b_modified
    FROM
      employee_state AS a1,
      employee_state AS a2
    WHERE
      a1.employee_id = a2.employee_id
      AND a1.state = changeFrom
      AND a1.end_date - a1.start_date < afterDays
      AND a2.state = changeTo
      AND a1.end_date + 1 = a2.start_date
  LOOP

    employee_id := rec.employee_id;
    a_employee_state_id := rec.a_employee_state_id;
    a_start_date := rec.a_start_date;
    a_end_date := rec.a_end_date;
    a_state := rec.a_state;
    a_created := rec.a_created;
    a_modified := rec.a_modified;
    b_employee_state_id := rec.b_employee_state_id;
    b_start_date:= rec.b_start_date;
    b_end_date := rec.b_end_date;
    b_state := rec.b_state;
    b_created := rec.b_created;
    b_modified := rec.b_modified;

    INSERT INTO
      employee_state
      (employee_id, start_date, end_date, state)
      VALUES
      (rec.employee_id, rec.a_start_date, rec.b_end_date, rec.b_state);

    DELETE FROM employee_state AS b
    WHERE b.employee_id = rec.employee_id
      AND b.start_date= rec.b_start_date
      AND b.end_date = rec.b_end_date
      AND b.state = rec.b_state;

    DELETE FROM employee_state AS b
    WHERE b.employee_id = rec.employee_id
      AND b.start_date= rec.a_start_date
      AND b.end_date = rec.a_end_date
      AND b.state = rec.a_state;
    return next;
  END LOOP;
END;
$$
LANGUAGE plpgsql;

我是 sql 菜鸟,所以请帮忙。谢谢。

--- 你可以用这个

创建table
CREATE TABLE employee_state (
  employee_state_id serial UNIQUE NOT NULL,
  employee_id int4 NOT NULL,
  start_date date NULL,
  end_date date NULL,
  state text null,
  created timestamp default now(),
  modified timestamp default now()
);

insert into employee_state (employee_id, start_date, end_date, state) values (1, '2008-12-15', '2008-12-31', '1');
insert into employee_state (employee_id, start_date, end_date, state) values (1, '2009-01-01', '2010-05-04', '2');

您的功能运行良好。您只需要像调用 table:

一样调用该函数
postgres=# delete from employee_state ;
DELETE 2
postgres=# insert into employee_state (employee_id, start_date, end_date, state) values (1, '2008-12-15', '2008-12-31', '1');
INSERT 0 1
postgres=# insert into employee_state (employee_id, start_date, end_date, state) values (1, '2009-01-01', '2010-05-04', '2');
INSERT 0 1
postgres=# select * from employee_state;
 employee_state_id | employee_id | start_date |  end_date  | state |          created           |          modified          
-------------------+-------------+------------+------------+-------+----------------------------+----------------------------
                 6 |           1 | 2008-12-15 | 2008-12-31 | 1     | 2020-02-13 06:31:56.942556 | 2020-02-13 06:31:56.942556
                 7 |           1 | 2009-01-01 | 2010-05-04 | 2     | 2020-02-13 06:31:57.024654 | 2020-02-13 06:31:57.024654
(2 rows)

postgres=# select combine('1', '2', 30);
                                                                                   combine                                                                                   
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 (1,6,2008-12-15,2008-12-31,1,"2020-02-13 06:31:56.942556","2020-02-13 06:31:56.942556",7,2009-01-01,2010-05-04,2,"2020-02-13 06:31:57.024654","2020-02-13 06:31:57.024654")
(1 row)

postgres=# delete from employee_state ;
DELETE 1
postgres=# insert into employee_state (employee_id, start_date, end_date, state) values (1, '2008-12-15', '2008-12-31', '1');
INSERT 0 1
postgres=# insert into employee_state (employee_id, start_date, end_date, state) values (1, '2009-01-01', '2010-05-04', '2');
INSERT 0 1
postgres=# select * from combine('1', '2', 30);
 employee_id | a_employee_state_id | a_start_date | a_end_date | a_state |         a_created          |         a_modified         | b_employee_state_id | b_start_date | b_end_date | b_state |         b
_created          |         b_modified         
-------------+---------------------+--------------+------------+---------+----------------------------+----------------------------+---------------------+--------------+------------+---------+----------
------------------+----------------------------
           1 |                   9 | 2008-12-15   | 2008-12-31 | 1       | 2020-02-13 06:32:12.635742 | 2020-02-13 06:32:12.635742 |                  10 | 2009-01-01   | 2010-05-04 | 2       | 2020-02-1
3 06:32:12.717752 | 2020-02-13 06:32:12.717752
(1 row)

披露:我为 EnterpriseDB (EDB)

工作