在 plpgsql 函数中访问 select 语句结果

Posted

技术标签:

【中文标题】在 plpgsql 函数中访问 select 语句结果【英文标题】:Access select statement result in plpgsql function 【发布时间】:2021-04-11 09:07:48 【问题描述】:

如何在 plpgsql 函数中访问 select 语句的结果以检查其内容?

我需要检查我使用的ilike 函数是否在我的people 表中返回任何匹配的演员。如果没有匹配项,我需要在“actor_details”表中返回“No matching name”,但如果有多个不同的值,我需要返回“Non-distinct actor name”之类的内容。

如果其中任何一个条件为真,我需要跳出函数并简单地在“actor_details”表中返回这些文本字符串。

在我的实际函数中,我需要在该语句之后附加几行文本,因此RETURNS table

任何指针都会很棒。最后两行代码中定义的预期输出。

CREATE TABLE people (
    id integer NOT NULL,
    name text NOT NULL,
    year_born integer,
    year_died integer
);

insert into people (id, name, year_born, year_died) values
(20000007,  'Humphrey Bogart',  1899,   1957)
(20000008,  'Marlon Brando',    1924,   2004)
(20000009,  'Richard Burton',   1925,   1984)
(200000010, 'Richard Hunt',     1985,   NULL)

CREATE OR REPLACE FUNCTION actor_details(_pattern text) 
RETURNS table (actor_details text) 
AS $$

BEGIN
  select distinct concat(people.name, ' (', people.year_born, '-', people.year_died, ')') 
    into actor_details
  from people
  where people.name ilike('%' || _pattern || '%');
  
  --- THIS IS WHERE I NEED HELP
  IF (@@ROWCOUNT = 0) then
    select 'No matching name' into actor_details;
  ELSIF (@@ROWCOUNT > 1) then
    select 'Non-distinct actor name';
  END IF; 
  return;              


END
$$ 
LANGUAGE plpgsql;

select * from actor_details('xxyyzz'); ---<<< Should return 'No matching name' in a column titled actor_details
select * from actor_details('Richarch'); ---<<< Should return 'Non-distinct actor name' in a column titled actor_details

【问题讨论】:

【参考方案1】:

我建议在查询中进行聚合以获取 actor_details:

select (case when count(*) = 0
             then 'No matching name'
             when count(distinct concat(p.name, ' (', p.year_born, '-', p.year_died, ')')) > 1
             then 'Non-distinct actor name'
             else max(concat(p.name, ' (', p.year_born, '-', p.year_died, ')'))
        end)
into actor_details
from people p
where p.name ilike('%' || _pattern || '%');

那么查询之后就不需要任何额外的逻辑了。

【讨论】:

当我 i) 替换 _pattern 变量的演员名称并自行运行查询或 ii) 在函数中使用建议时,我收到错误消息“在“then”处或附近出现语法错误本身。我该如何解决? @dominiquealpinski 。 . .这只是 when 子句中缺少的结束括号。【参考方案2】:

您可以使用UNION ALL 和三个根据匹配数选择字符串的查询来做到这一点。你甚至不需要 PL/pgSQL。 (你想要一个只包含一个值的集合似乎很奇怪。简单地返回一个标量可能更有意义。)

CREATE
 OR REPLACE FUNCTION actor_details
                     (_pattern text) 
                     RETURNS table
                             (actor_details text) 
AS
$$
SELECT concat(people.name,
              ' (',
              people.year_born,
              '-',
              people.year_died,
              ')')
       FROM people
       WHERE people.name ILIKE '%' || _pattern || '%'
             AND (SELECT count(*)
                         FROM people
                         WHERE people.name ILIKE '%' || _pattern || '%') = 1
UNION ALL
SELECT 'No matching name'
       WHERE (SELECT count(*)
                     FROM people
                     WHERE people.name ILIKE '%' || _pattern || '%') = 0
UNION ALL
SELECT 'Non-distinct actor name'
       WHERE (SELECT count(*)
                     FROM people
                     WHERE people.name ILIKE '%' || _pattern || '%') > 1;
$$ 
LANGUAGE sql;

db<>fiddle

【讨论】:

是否可以保留我在上面示例中使用的格式?我问是因为在此操作完成后,我需要将每个演员所在的电影列表附加到表“actor_details”中。使用建议的答案会产生一个函数,该函数返回表中的电影列表,但不返回演员姓名(或出生/死亡年份)。 似乎提出的问题有几个令人满意的答案。你应该接受其中之一。如果您现在还需要从另一个表中获取数据,那么您需要提出另一个问题。 提示这将涉及一个Join。

以上是关于在 plpgsql 函数中访问 select 语句结果的主要内容,如果未能解决你的问题,请参考以下文章

返回查询时如何退出plpgsql函数

通过 RAW plpgsql 中的 UPDATE 语句获取受影响的行

检查 plpgsql 中的当前日志记录级别

返回多列的plpgsql函数被多次调用

如何在 plpgsql 函数中获取表的关键字段?

光标检索在 plpgsql 函数中创建的表中已删除的行