PL/pgSQL:触发函数返回不正确的数据
Posted
技术标签:
【中文标题】PL/pgSQL:触发函数返回不正确的数据【英文标题】:PL/pgSQL: Trigger Function returning incorrect data 【发布时间】:2021-12-08 09:14:56 【问题描述】:我有一个带有参数“select_date”和“sponsor”的函数,它应该根据作为参数传递的值返回一些数据表:
SET search_path to Olympic;
CREATE OR REPLACE FUNCTION fn_get_info_by_sponsor
(register_date tb_register.register_ts%type, sponsor_name tb_finance.sponsor_name%type)
RETURNS SETOF sponsor_data LANGUAGE plpgsql AS $$
DECLARE
sp_data sponsor_data ;
BEGIN
SELECT
tb_sponsor.email,
tb_finance.sponsor_name,
tb_athlete.name,
tb_discipline.name,
tb_register.round_number,
tb_register.register_measure,
tb_register.register_position,
DATE(tb_register.register_ts)
INTO sp_data
FROM olympic.tb_sponsor
INNER JOIN olympic.tb_finance
ON (tb_finance.sponsor_name = tb_sponsor.name)
INNER JOIN olympic.tb_athlete
ON tb_athlete.athlete_id = tb_finance.athlete_id
INNER JOIN olympic.tb_register
ON tb_register.athlete_id = tb_athlete.athlete_id
INNER JOIN olympic.tb_discipline
ON tb_discipline.discipline_id = tb_register.discipline_id
ORDER BY tb_sponsor.email ;
RETURN NEXT sp_data ;
END ;
$$;
该函数部分工作,但它返回不正确的值。当我使用参数 '2021-06-02 00:00:00', 'Adidas' 其中 'Adidas' 是赞助商时,它会将赞助商名称返回为 VISA:
SELECT * FROM fn_get_info_by_sponsor('2021-06-02 00:00:00', 'Adidas')
sponsor email, sponsor_name, athlete_name, discipline_name, round_number, register_measure, register_position, register_ts,
NULL "VISA" "JACOBY Lydia" "Swimming" 1 NULL 3 "2021-06-07"
谁能看出我做错了什么?
谢谢!
CREATE TYPE sponsor_data AS (
email email_type,
sponsor_name CHARACTER VARYING(100),
athletes_name CHARACTER VARYING(50),
discilpine_name CHARACTER VARYING(50),
round_number INT ,
mark CHARACTER(12),
register_position INT,
register_ts DATE
);
【问题讨论】:
好吧,您不要使用 WHERE 子句中的参数来限制结果。而且您也只返回查询的第一行。 @a_horse_with_no_name SETOF 语句是否应该返回行集? 不,“return”语句从函数返回一些东西。您正在使用您的 return 语句返回一行。 你运行return next
一次,所以你只返回一行。
RETURN SETOF
是函数定义的一部分。它不返回任何东西。 return next
每次运行时返回一行。您的代码只运行return next
一次,因此您的函数将永远不会返回超过一行。
【参考方案1】:
对于返回 setof
的 PL/pgSQL 函数,您必须使用 RETURN QUERY
子句,请参阅 manual :
CREATE OR REPLACE FUNCTION fn_get_info_by_sponsor
(register_date tb_register.register_ts%type, sponsor_name tb_finance.sponsor_name%type)
RETURNS SETOF sponsor_data LANGUAGE plpgsql AS $$
BEGIN
RETURN QUERY
SELECT row(
tb_sponsor.email,
tb_finance.sponsor_name,
tb_athlete.name,
tb_discipline.name,
tb_register.round_number,
tb_register.register_measure,
tb_register.register_position,
DATE(tb_register.register_ts)
) :: sponsor_data
FROM olympic.tb_sponsor
INNER JOIN olympic.tb_finance
ON (tb_finance.sponsor_name = tb_sponsor.name)
INNER JOIN olympic.tb_athlete
ON tb_athlete.athlete_id = tb_finance.athlete_id
INNER JOIN olympic.tb_register
ON tb_register.athlete_id = tb_athlete.athlete_id
INNER JOIN olympic.tb_discipline
ON tb_discipline.discipline_id = tb_register.discipline_id
ORDER BY tb_sponsor.email ;
END ;
$$;
或者您可以简单地编写一个 SQL 用户定义函数:
CREATE OR REPLACE FUNCTION fn_get_info_by_sponsor
(register_date tb_register.register_ts%type, sponsor_name tb_finance.sponsor_name%type)
RETURNS SETOF sponsor_data LANGUAGE sql AS $$
SELECT row(
tb_sponsor.email,
tb_finance.sponsor_name,
tb_athlete.name,
tb_discipline.name,
tb_register.round_number,
tb_register.register_measure,
tb_register.register_position,
DATE(tb_register.register_ts)
) :: sponsor_data
FROM olympic.tb_sponsor
INNER JOIN olympic.tb_finance
ON (tb_finance.sponsor_name = tb_sponsor.name)
INNER JOIN olympic.tb_athlete
ON tb_athlete.athlete_id = tb_finance.athlete_id
INNER JOIN olympic.tb_register
ON tb_register.athlete_id = tb_athlete.athlete_id
INNER JOIN olympic.tb_discipline
ON tb_discipline.discipline_id = tb_register.discipline_id
ORDER BY tb_sponsor.email ;
$$;
【讨论】:
谢谢(:返回查询没有解决我的问题。我收到:错误:无法打开 SELECT 查询作为光标。 您的问题不在函数fn_get_info_by_sponsor
内,而在于您在CURSOR
内调用此函数的方式!请显示调用函数fn_get_info_by_sponsor
的函数代码。
这就是我调用函数的方式:SELECT * FROM fn_get_info_by_sponsor('2021-06-02 00:00:00', 'Adidas')
我已经更新了我的答案,但我不确定它是否能解决您的错误。您能否创建表格定义并在dbfiddle 中插入数据样本,以便我们分析您的问题?以上是关于PL/pgSQL:触发函数返回不正确的数据的主要内容,如果未能解决你的问题,请参考以下文章
重构 PL/pgSQL 函数以返回各种 SELECT 查询的输出