【问题标题】:PostgreSQL: select all rows with a condition if it exists, else ignore the condition and select the earliest rowPostgreSQL:如果存在,则选择所有具有条件的行,否则忽略条件并选择最早的行
【发布时间】:2017-05-25 17:30:34
【问题描述】:

我有一个返回 SETOF records 的 PostgreSQL 函数 find_all_records_with_params()。记录表有以下列:

table records(
id integer,
type integer,
created date,
content text
);

我想选择 current_date - created 大于 90 天的所有记录。但是,如果此查询不存在,我想选择 1 条最早 created 日期的记录。

我尝试使用递归 cte(如下所示)来执行此操作,但它不允许 if/else 逻辑。我试图避免调用find_all_records_with_params() 函数两次,如果可能的话,我不希望创建临时表。

with most_records as (select * from find_all_records_with_params()),
filtered_records as (select * from most_records where current_date - created > 90)
if exists(select * from filtered_records) then
select * from filtered_records;
else
select * from most_records order by created asc limit 1;
end if;

【问题讨论】:

  • current_date - created > 90 -- 这很丑。为什么不created < current_date - 90
  • @DavidAldridge 执行current_date - 90 是否比current_date - created 有性能优势?它会缓存该值吗?
  • 它允许优化器使用索引,但更容易阅读——我写 SQL 已经 25 年了,但你把 current_date - created > 90 放在我面前,我必须好好想想这意味着什么。

标签: sql postgresql common-table-expression


【解决方案1】:
with most_records as (select * from find_all_records_with_params()),
filtered_records as (select * from most_records where current_date - created > 90)
select * from filtered_records
union 
select * from 
(select * from most_records 
where not exists (select * from filtered_records limit 1) 
order by created asc limit 1 ) a ;

我已使用联合查询来实现您所需的结果。如果您的过滤记录返回结果,则联合后查询不会产生任何结果,否则联合后查询会产生结果。

【讨论】:

  • 谢谢!当你做where not exists (select * from filtered_records limit 1) 时,limit 1做什么?
  • 在不存在的地方(子查询限制1),这里的限制是用来减少执行时间的。因为我们只需要检查过滤记录中是否有记录。
猜你喜欢
  • 2014-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-19
  • 2017-01-13
  • 2017-11-23
相关资源
最近更新 更多