创建一个接受字符串并返回多行的函数

Posted

技术标签:

【中文标题】创建一个接受字符串并返回多行的函数【英文标题】:Create a function that accepts a string and returns multiple rows 【发布时间】:2021-11-29 05:54:51 【问题描述】:

我需要创建一个函数来根据用户的输入转换单个列的值。我需要一些关于这样做的语法方面的帮助。

这是我当前为获取行而执行的查询:

SELECT payment_id, rental_id, amount FROM payment

我正在尝试做的一些伪代码:

function getReport(String currencyType)
    if(currencyType == 'EUR')

       Multiply the values in the amounts column by 1.16 and append Euros to it
       Return all the rows in the table

    else if(currencyType == 'RMB')

       Multiple the values in the amounts column by 6.44 and append RMB to it
       Return all the rows in the table

    else

       Do nothing because the default column values are in USD
       Return all the rows in the table

    

我一直在尝试创建一个,但我在语法上遇到了困难。 不工作:

CREATE OR REPLACE FUNCTION get_data(currency_type text) RETURNS TABLE payment_info AS $$
    CASE currency_type
    WHEN 'EUR' THEN
        SELECT payment_id, rental_id, amount * 1.16 FROM payment;
    WHEN 'RMB' THEN
        SELECT payment_id, rental_id, amount * 6.44 FROM payment;
    WHEN 'USD' THEN
        SELECT payment_id, rental_id, amount FROM payment;
$$ LANGUAGE SQL;

有人可以帮助我了解创建此函数的语法吗?

【问题讨论】:

您最好阅读CASE。提示你不能嵌套SELECT 【参考方案1】:

类似的东西

CREATE OR REPLACE FUNCTION get_data(currency_type text) 
RETURNS TABLE  ( payment_id int, rental_id int, amount numeric(5,2) ) 
language plpgsql
as $$
begin 
   return query 
     SELECT b.payment_id, b.rental_id, 
    case 
        when currency_type = 'EUR' then b.amount * 1.16     
        when currency_type = 'RMB' then b.amount * 6.44 
        when currency_type = 'USD' then b.amount 
    end as amount 
    FROM payment b;
end;$$

如果你使用它确实会以表格的形式返回

select * from get_data('EUR');

这里有一个演示

demo in db<>fiddle

【讨论】:

哦,我认为 RETURNS TABLE 会将它们作为单独的列返回,但它会将其作为包含所有值的一列发送回来。我将如何返回它,以便返回上面屏幕截图中的所有 3 列? 我用 dbfiddle 中的新演示更新了帖子。它确实以表格的形式返回记录。 @DIRTYDAVE,你检查我更新的数据库fiddle 了吗?它以表格的格式显示结果,其中包含您所期望的列。如果是这样,如果您支持并接受答案,我将不胜感激,当然如果它解决了您的问题。 是的,刚试过,我没有加星号,只用了select get_data('EUR');。效果很好,谢谢! @DIRTYDAVE,不客气;)【参考方案2】:

Postgres 14 或更高版本

在 Postgres 14 或更高版本中,我建议使用新的标准 SQL 语法:

CREATE OR REPLACE FUNCTION get_data(_currency_type text DEFAULT 'USD')
  RETURNS TABLE (payment_id int, rental_id int, amount numeric(5,2)) 
  STABLE PARALLEL SAFE
BEGIN ATOMIC
SELECT p.payment_id, p.rental_id
     , CASE _currency_type
          WHEN 'USD' THEN p.amount
          WHEN 'EUR' THEN p.amount * 1.16
          WHEN 'RMB' THEN p.amount * 6.44
FROM   payment p;
END;

见:

What does BEGIN ATOMIC ... END mean in a Postgresql SQL function / procedure?

以下大部分内容仍然适用...

Postgres 13(或任何版本)

CREATE OR REPLACE FUNCTION get_data(_currency_type text DEFAULT 'USD')
  RETURNS TABLE  (payment_id int, rental_id int, amount numeric(5,2)) 
  LANGUAGE sql STABLE PARALLEL SAFE AS
$func$
SELECT p.payment_id, p.rental_id
     , CASE _currency_type
          WHEN 'USD' THEN p.amount
          WHEN 'EUR' THEN p.amount * 1.16
          WHEN 'RMB' THEN p.amount * 6.44 
       -- ELSE 1/0 END   -- ??? this purposely raises an exception
FROM   payment p;
$func$;

坚持使用 LANGUAGE sql(就像您最初的尝试一样)。简单函数不需要LANGUAGE plpgsql - 除非您想为无效输入添加自定义错误消息或错误处理..

见:

Difference between language sql and language plpgsql in PostgreSQL functions

使用更简单的切换CASE(就像您最初的尝试一样)。

Display column name with max value between several columns Simplify nested case when statement

提供明确的 ELSE 分支。 (SQL CASE 默认为 NULL,如果 ELSE 没有拼写出来。)

如果您最初尝试中的 payment_info 是与您所需的返回类型匹配的现有行类型,请使用简单的 RETURNS SETOF payment_info 而不是 RETURNS TABLE(...)

用可能的不明确的名称表格限定列是一种很好的风格,就像演示的那样。 (无论如何,这绝不是个坏主意。) 但这是LANGUAGE plpgsql 函数中的要求,其中RETURNS TABLE ...) 隐式声明OUT 参数与表列同名。这会引发如下异常:

错误:列引用“payment_id”不明确

见:

INSERT INTO ... RETURNING - ambiguous column reference How to return result of a SELECT inside a function in PostgreSQL?

另外:numeric(5,2)? 这引发了amount &gt; 999.99 的异常。看起来像一把上膛的脚枪。只需使用numericnumeric(20,2) 之类的东西即可获得舍入效果。

关于STABLE

How do IMMUTABLE, STABLE and VOLATILE keywords effect behaviour of function?

关于PARALLEL SAFE

When to mark functions as PARALLEL RESTRICTED vs PARALLEL SAFE?

最后,正如已经清理的那样,分解结果行,调用 SELECT * FROM

SELECT * FROM get_data('USD');

见:

Simple PostgreSQL function to return rows PostgreSQL: ERROR: 42601: a column definition list is required for functions returning "record"

我为输入参数添加了一个默认值DEFAULT 'USD'。这很方便,但完全是可选的。它记录了最常见的预期,并允许在没有显式参数的情况下进行短调用:

SELECT * FROM get_data();

【讨论】:

以上是关于创建一个接受字符串并返回多行的函数的主要内容,如果未能解决你的问题,请参考以下文章

在 TypeScript 中,如何声明一个接受字符串并返回字符串的函数数组?

如何创建一个接受查询字符串并返回查询结果集的 UDF

javascript 一个接受多个便士并返回表示美元和美分数量的字符串的函数。

单行函数

javascript 编写一个函数,该函数接受一个字符串数组并返回该数组中最常出现的字符串。如果有多个字符串

编写一个函数读取 number(s, i),它接受一个字符串 s 和一个整数 I,并返回一个由以下组成的对