【问题标题】:Sending one record from cursor to another function Postgres将一条记录从光标发送到另一个函数 Postgres
【发布时间】:2010-04-26 18:44:35
【问题描述】:

仅供参考:我对使用游标完全陌生... 所以我有一个函数是光标:

CREATE FUNCTION get_all_product_promos(refcursor, cursor_object_id integer) RETURNS refcursor AS '
BEGIN
    OPEN $1 FOR SELECT *
                FROM promos prom1
                JOIN promo_objects ON (prom1.promo_id = promo_objects.promotion_id)
                WHERE prom1.active = true AND now() BETWEEN prom1.start_date AND prom1.end_date
                    AND promo_objects.object_id = cursor_object_id
                UNION 
                SELECT prom2.promo_id 
                FROM promos prom2 
                JOIN promo_buy_objects ON (prom2.promo_id = 
                    promo_buy_objects.promo_id)
                LEFT JOIN promo_get_objects ON prom2.promo_id = promo_get_objects.promo_id
                WHERE (prom2.buy_quantity IS NOT NULL OR prom2.buy_quantity > 0) AND
                    prom2.active = true AND now() BETWEEN prom2.start_date AND  
                    prom2.end_date AND promo_buy_objects.object_id = cursor_object_id;
    RETURN $1;
END;
' LANGUAGE plpgsql;

然后在另一个函数中我调用它并需要处理它:

...
--Get the promotions from the cursor
        SELECT get_all_product_promos('promo_cursor', this_object_id)
        updated := FALSE;
        IF FOUND THEN
        --Then loop through your results
            LOOP
                FETCH promo_cursor into this_promotion
                --Preform comparison logic -this is necessary as this logic is used in other contexts from other functions
                SELECT * INTO best_promo_results FROM get_best_product_promos(this_promotion, this_object_id, get_free_promotion, get_free_promotion_value, current_promotion_value, current_promotion);
...

所以这里的想法是从游标中选择,使用 fetch 循环(假设下一个正确?)并将获取的记录放入 this_promotion。然后将 this_promotion 中的记录发送到另一个函数。我不知道在 get_best_product_promos 中声明 this_promotion 的类型是什么。这是我所拥有的:

CREATE OR REPLACE FUNCTION get_best_product_promos(this_promotion record, this_object_id integer, get_free_promotion integer, get_free_promotion_value numeric(10,2), current_promotion_value numeric(10,2), current_promotion integer)
  RETURNS...

它告诉我:错误:plpgsql 函数不能采用类型记录

好的,我先试试:

CREATE OR REPLACE FUNCTION get_best_product_promos(this_promotion get_all_product_promos, this_object_id integer, get_free_promotion integer, get_free_promotion_value numeric(10,2), current_promotion_value numeric(10,2), current_promotion integer)
  RETURNS...

因为我在 Postgres 文档中看到了一些语法,显示了一个正在创建的函数,该函数带有一个类型为“表名”的输入参数,这是可行的,但它必须是表名而不是函数:( 我知道我很接近,我被告知使用游标传递记录。所以我研究了。请帮助。

【问题讨论】:

    标签: postgresql stored-procedures resultset cursors


    【解决方案1】:

    一种可能性是将您在 get_all_product_promos 中的查询定义为 all_product_promos 视图。然后你会自动让“all_product_promos%rowtype”类型在函数之间传递。

    也就是说,类似于:

    CREATE VIEW all_product_promos AS
    SELECT promo_objects.object_id, prom1.*
    FROM promos prom1
    JOIN promo_objects ON (prom1.promo_id = promo_objects.promotion_id)
    WHERE prom1.active = true AND now() BETWEEN prom1.start_date AND prom1.end_date
    UNION ALL
    SELECT promo_buy_objects.object_id, prom2.*
    FROM promos prom2
         JOIN promo_buy_objects ON (prom2.promo_id = promo_buy_objects.promo_id)
         LEFT JOIN promo_get_objects ON prom2.promo_id = promo_get_objects.promo_id
    WHERE (prom2.buy_quantity IS NOT NULL OR prom2.buy_quantity > 0)
          AND prom2.active = true
          AND now() BETWEEN prom2.start_date AND prom2.end_date
    

    您应该能够使用 EXPLAIN 验证查询 SELECT * FROM all_product_promos WHERE object_id = ? 将 object_id 参数带入两个子查询,而不是事后过滤。然后你可以从另一个函数编写:

    DECLARE
      this_promotion all_product_promos%ROWTYPE;
    BEGIN
      FOR this_promotion IN
            SELECT * FROM all_product_promos WHERE object_id = this_object_id
      LOOP
         -- deal with promotion in this_promotion
      END LOOP;
    END
    

    TBH 我会避免使用游标在 PLPGSQL 中传递记录。事实上,我会避免在 PLPGSQL 句号中使用游标——除非你出于某种原因需要将整个结果集传递给另一个函数。这种简单循环语句的方法要简单得多,但需要注意的是整个结果集首先被具体化到内存中。

    这种方法的另一个缺点是,如果您需要向 all_product_promos 添加列,则需要重新创建依赖它的所有函数,因为您无法使用“alter view”将列添加到视图。 AFAICT 这也会影响使用CREATE TYPE 创建的命名类型,因为ALTER TYPE 似乎也不允许您将列添加到类型中。

    因此,您可以使用“CREATE TYPE”指定记录格式以在函数之间传递。任何关系都会自动指定一个名为 <relation>%ROWTYPE 的类型,您也可以使用它。

    【讨论】:

    • 哦,哇,是的,视图更有意义,我被函数所吸引,以至于我在盒子里思考。是的,我现在遇到了我的 FETCH 语句的问题,错误让我陷入了循环。我更熟悉使用视图,我也不喜欢光标的想法。这是我第一次不得不如此紧张地工作,这让我不知所措。感谢您的提示,现在我必须重新考虑我尝试了两天的工作,但可惜它仍然不起作用哈。
    • WOOHOO 查询返回成功!耶!谢谢你,这对于必须在我身后进行挑选的人来说更容易理解。谢谢!!!
    【解决方案2】:

    答案:

    在光标函数中选择特定字段而不是*

    然后:

    CREATE TYPE get_all_product_promos as (buy_quantity integer, discount_amount numeric(10,2), get_quantity integer, discount_type integer, promo_id integer);
    

    那我可以说:

    CREATE OR REPLACE FUNCTION get_best_product_promos(this_promotion get_all_product_promos, this_object_id integer, get_free_promotion integer, get_free_promotion_value numeric(10,2), current_promotion_value numeric(10,2), current_promotion integer)
      RETURNS...
    

    【讨论】:

    • 仅供参考,如果您使用游标,这确实有效,我原始代码中的 FETCH 语句引发了我或谷歌无法识别的错误,这不是语法错误,但我选择了观点,因为我倾向于同意 araqmod 的所有观点
    猜你喜欢
    • 1970-01-01
    • 2020-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-11
    相关资源
    最近更新 更多