Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/.htaccess/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PostgreSQL。存储函数或查询改进_Postgresql_Plpgsql - Fatal编程技术网

PostgreSQL。存储函数或查询改进

PostgreSQL。存储函数或查询改进,postgresql,plpgsql,Postgresql,Plpgsql,我使用的是PostgreSQL,并且有一个员工表: employeeid | FirstName | LastName | Department | Position 1 | Aaaa | | | 2 | Bbbb | | | 3 | | | | . |

我使用的是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
     .     |         ...         |                     
报告表格:

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; 
在我看来,这不是一个理想的解决方案。有没有更好的方法来达到同样的效果?
谢谢。

你说得对:在关系数据库中,循环通常是一种不好的方法

您可以在普通SQL中执行此操作:

select e.employeeid, e.lastname, e.firstname, e.department, e.position 
from employee e
where not exists (select *
                  from reports r
                  where r.enter::date = date '2020-11-08'
                    and e.employeeid = r.employeeid);

这将返回2020-11-08上的
报告
表中不存在行的所有员工您是对的:通常情况下,循环是在关系数据库中执行操作的糟糕方式

您可以在普通SQL中执行此操作:

select e.employeeid, e.lastname, e.firstname, e.department, e.position 
from employee e
where not exists (select *
                  from reports r
                  where r.enter::date = date '2020-11-08'
                    and e.employeeid = r.employeeid);

这将返回2020-11-08的
报告
表中不存在行的所有员工

您的代码非常无效。也许它不会写得很差:-)。回复@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_和_no_name提出的解决方案是一个查询(没有plpgsql的开销)。我的任何示例都有
employees+1
查询(plpgsql的开销较低)


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

您的代码非常无效。也许它不会写得很差:-)。回复@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_和_no_name提出的解决方案是一个查询(没有plpgsql的开销)。我的任何示例都有
employees+1
查询(plpgsql的开销较低)


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

感谢您花时间提供帮助!这就是我要找的!感谢您抽出时间和帮助!这就是我要找的!谢谢你的深刻解释。还有一个问题:如果我在这段时间内需要结果如何?例如From=
2020-11-0
,To=
2020-11-08
。结果
employeeid,lastname,firstname,department,position,misseddate
@Ma'ruf-这不是一个问题,你可以在
操作符之间使用
。当查询结果的结构与预期结果不同时,可以使用自定义复合类型。几乎所有这些都是可能的——plpgsql和SQL是成熟的语言。请从plpgsql文档阅读开始—它只有不到50页,您将看到所有的可能性—返回表中的misseddate列如何?现在我正在更新我的问题。
返回表(…)
中的标识符也是
OUT
变量。因此,您可以填充这些变量并使用无参数的
RETURN NEXT
,或者您可以在
REURN NEXT
中使用复合值,如
RETURN NEXT(r.employeeid,r…,\u f_from_date)
。那么,这是在日期范围内循环的正确方法吗<代码>\u res=f_to-f_from
用于0..u res中的i
循环
\u from=f\u from+i感谢您的深入解释。还有一个问题:如果我在这段时间内需要结果如何?例如From=
2020-11-0
,To=
2020-11-08
。结果
employeeid,lastname,firstname,department,position,misseddate
@Ma'ruf-这不是一个问题,你可以在
操作符之间使用
。当查询结果的结构与预期结果不同时,可以使用自定义复合类型。几乎所有这些都是可能的——plpgsql和SQL是成熟的语言。请从plpgsql文档阅读开始—它只有不到50页,您将看到所有的可能性—返回表中的misseddate列如何?现在我正在更新我的问题。
返回表(…)
中的标识符也是
OUT
变量。因此,您可以填充这些变量并使用无参数的
RETURN NEXT
,或者您可以在
REURN NEXT
中使用复合值,如
RETURN NEXT(r.employeeid,r…,\u f_from_date)
。那么,这是在日期范围内循环的正确方法吗<代码>\u res=f_to-f_from
用于0..u res中的i
循环
\u from=f\u from+i如果你有一个新问题,然后问一个新问题(可能会链接回这个问题)。如果你有一个新问题,不要扩展你现有的问题,然后问一个新问题(可能会链接回这个问题)。不要扩展现有的