创建一个接受字符串并返回多行的函数
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
(就像您最初的尝试一样)。
提供明确的 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 > 999.99
的异常。看起来像一把上膛的脚枪。只需使用numeric
或numeric(20,2)
之类的东西即可获得舍入效果。
关于STABLE
:
关于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 中,如何声明一个接受字符串并返回字符串的函数数组?
javascript 一个接受多个便士并返回表示美元和美分数量的字符串的函数。