postgresql 功能:如果 Select 没有返回任何内容,则执行另一个 Select

Posted

技术标签:

【中文标题】postgresql 功能:如果 Select 没有返回任何内容,则执行另一个 Select【英文标题】:postgresql FUNCTION: If Select returns nothing then do another Select 【发布时间】:2021-11-19 04:14:42 【问题描述】:

请帮助我创建 postgresql FUNCTION。

我有两个疑问:

如果第一个没有返回值

SELECT * FROM event e
    WHERE e.organizer_id IN (SELECT u.id FROM "user" u WHERE u.school_id = 9)
    OR e.id IN (SELECT i.event_id FROM invite i WHERE i.user_id IN (SELECT u.id FROM "user" u WHERE u.school_id = 9));

那么我需要调用第二个查询

SELECT * FROM event e 
    INNER JOIN user u on u.id = e.organizer_id  
    INNER JOIN school s on u.school_id = s.id
WHERE u.school_id = :schoolId and ST_DWithin(ST_Transform(e.geom, 2163), ST_Transform(s.geom,2163), :radius * 1609.34)

我试图创建一个函数但卡住了。我对SQL没有太多经验,请帮忙。

我是这样想的:

CREATE FUNCTION all_nearby_events(mySchoolID INT) RETURNS event AS $$
DECLARE
    user_ids bigserial; -- save List of user ids because i need it twice
BEGIN
    user_ids :=(SELECT u.id FROM "user" u WHERE u.school_id = mySchoolID);

    SELECT * FROM event e
                      INNER JOIN user u on u.id = e.organizer_id
                      INNER JOIN school s on u.school_id = s.id
    WHERE u.school_id = :schoolId and ST_DWithin(ST_Transform(e.geom, 2163), ST_Transform(s.geom,2163), :radius * 1609.34)

      and not exists (
            SELECT * FROM event e WHERE e.organizer_id IN (user_ids) OR e.id IN (SELECT i.event_id FROM invite i WHERE i.user_id IN (user_ids))
        )
    union all
    SELECT * FROM event e WHERE e.organizer_id IN (user_ids) OR e.id IN (SELECT i.event_id FROM invite i WHERE i.user_id IN (user_ids));
END;
$$
LANGUAGE plpgsql;

【问题讨论】:

【参考方案1】:

使用return query 并检查found 内置变量。 请注意returns SETOF。我假设您的查询很好,除了myschoolidmax_radius 参数之外,它们或多或少没有变化。

create or replace function all_nearby_events(myschoolid integer, max_radius numeric)
returns SETOF event as
$$
begin

 return query -- your first query follows
    SELECT * FROM event e
    WHERE e.organizer_id IN (SELECT u.id FROM "user" u WHERE u.school_id = myschoolid)
    OR e.id IN (SELECT i.event_id FROM invite i WHERE i.user_id IN (SELECT u.id FROM "user" u WHERE u.school_id = myschoolid));

 if found then return; end if;

 return query -- your second query follows
    SELECT * FROM event e 
    INNER JOIN user u on u.id = e.organizer_id  
    INNER JOIN school s on u.school_id = s.id
    WHERE u.school_id = myschoolid and ST_DWithin(ST_Transform(e.geom, 2163), ST_Transform(s.geom,2163), max_radius * 1609.34);

 -- more queries can follow here

end;
$$ language plpgsql;

编辑 这是一个建议(虽然不是最理想的),如果没有 plpgsql 函数,您如何做到这一点。

with t as
(
 select 
   1 as query_order, event.* 
   -- the rest of your first query here
 union all
   2 as query_order, event.* 
   -- the rest of your second query here

   -- more queries can follow here
)
select * from t 
where query_order = (select min(query_order) from t);

【讨论】:

感谢您的回答。另一个经验问题。是否可以在没有程序的情况下解决此问题?我的意思是把这两个 SELECT 合二为一。 你能检查一下FINAL块吗? 什么是最终块? 我更新了你的答案并添加了 SQL 标记为粗体 FINAL 我明白了。不幸的是,它不是有效的 SQL。它应该是` ... select * from t WHERE t.name ~* 'event title string' LIMIT 1000 OFFSET 0`。请。请注意,我没有调查您的业务逻辑。

以上是关于postgresql 功能:如果 Select 没有返回任何内容,则执行另一个 Select的主要内容,如果未能解决你的问题,请参考以下文章

Oracle实现POSTGRESQL的generate_series功能

如果在sql postgresql中存在,如何使用

PostgreSQL SELECT 语句

PostgreSQL SELECT 语句

随便玩玩之PostgreSQL(第二章)单表数据查询

列出引用 PostgreSQL 中表的存储函数