首页 > 解决方案 > PostgreSQL。存储函数或查询改进

问题描述

我正在使用PostgreSQL并且有一个员工表:

employeeid | FirstName | LastName | Department | Position
    1      | Aaaa      |          |            |
    2      | Bbbb      |          |            |
    3      |           |          |            |
    .      |           |          |            |

报告表:

employeeid |        enter        |        exit
     1     | 2020-11-08 09:02:21 | 2020-11-08 18:12:01
     .     |         ...         |                     

现在,我正在查询某个日期错过的员工,类似于该功能:

for i in select employeeid from employee
loop
    if select not exists(select 1 from reports where enter::date = '2020-11-08' and employeeid = i) then
       return query select employeeid, lastname, firstname, department, position from employee where employeeid = i;        
    end if;
end loop; 

在我看来,这不是一个理想的解决方案。有没有更好的方法来达到相同的结果?谢谢。

标签: postgresqlplpgsql

解决方案


您的代码非常无效。可能它不能写得不好:-)。回复@a_horse_with_no_name 是绝对正确的,只是为了完整起见,我将修复您的 plpgsql 代码。

DECLARE _e employee;
BEGIN
  FOR _e IN SELECT * FROM employee
  LOOP
    IF NOT EXISTS(SELECT * 
                    FROM reports r
                   WHERE r.enter::date = date '2020-11-08'
                     AND r.employeeid = _e.employeeid)
    THEN
      RETURN NEXT _e;
    END IF;
  END LOOP;
END;

当您编写存储过程(或任何基于查询的应用程序)时,重要的值是查询的数量 - 数量越少越好(注意 - 有例外 - 有时过于复杂的查询可能会因为它们的复杂性而变慢)。在您的示例中,有employees * 2 + 1查询(plpgsql 的开销更大 -RETURN QUERY比 更昂贵RETURN NEXT)。@a_horse_with_no_name 提出的解决方案是一个查询(没有 plpgsql 的开销)。我的任何示例都有employees + 1查询(plpgsql 的开销较低)。

您的示例是一种常见 SQL 反模式的好示例 - “使用 ISAM 样式”。


推荐阅读