【问题标题】: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

标签: sql postgresql function set-returning-functions create-function


【解决方案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;

见:

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

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 分支。 (SQL CASE 默认为 NULL,如果 ELSE 没有拼写出来。)

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

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

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

见:

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

关于STABLE

关于PARALLEL SAFE

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

SELECT * FROM get_data('USD');

见:

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

SELECT * FROM get_data();

【讨论】:

    猜你喜欢
    • 2021-02-16
    • 1970-01-01
    • 1970-01-01
    • 2015-02-10
    • 1970-01-01
    • 2022-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多