PostgreSQL。存储函数或查询改进
我使用的是PostgreSQL,并且有一个员工表:PostgreSQL。存储函数或查询改进,postgresql,plpgsql,Postgresql,Plpgsql,我使用的是PostgreSQL,并且有一个员工表: employeeid | FirstName | LastName | Department | Position 1 | Aaaa | | | 2 | Bbbb | | | 3 | | | | . |
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代码>如果你有一个新问题,然后问一个新问题(可能会链接回这个问题)。如果你有一个新问题,不要扩展你现有的问题,然后问一个新问题(可能会链接回这个问题)。不要扩展现有的