0

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

这是我当前正在执行以获取行的查询:

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;

有人可以帮我创建这个函数的语法吗?

4

2 回答 2

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');

这里有一个演示

db<>fiddle 中的演示

于 2021-10-09T20:34:52.943 回答
1

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;

看:

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

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简单功能 - 除非您想为无效输入添加自定义错误消息或错误处理..

看:

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

提供明确的ELSE分支。(SQLCASE默认为NULLifELSE没有拼写出来。)

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

用可能模棱两可的名称对列进行表限定是一种很好的风格,例如演示。(在任何情况下这都不是一个坏主意。) 但这是隐式声明与表列同名的参数的函数的要求。这会引发如下异常:
LANGUAGE plpgsqlRETURNS TABLE ...)OUT

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

看:

还有:numeric(5,2)这引发了amount > 999.99. 看起来像一把上膛的脚枪。只需使用numeric或类似的东西numeric(20,2)来实现四舍五入效果。

关于STABLE

关于PARALLEL SAFE

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

SELECT * FROM get_data('USD');

看:

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

SELECT * FROM get_data();
于 2021-10-10T01:20:23.267 回答