【问题标题】:PostgreSQL - Iterate over results of queryPostgreSQL - 遍历查询结果
【发布时间】:2015-12-16 13:23:53
【问题描述】:

我正在用 pgsql 脚本语言创建一个函数,此时我想做的是遍历查询的结果,并为每一行做一些特定的事情。我目前的尝试如下,其中temprow 被声明为temprow user_data.users%rowtype。有问题的代码如下:

FOR temprow IN
        SELECT * FROM user_data.users ORDER BY user_seasonpts DESC LIMIT 10
    LOOP
        SELECT user_id,user_seasonpts INTO player_idd,season_ptss FROM temprow;
        INSERT INTO user_data.leaderboards (season_num,player_id,season_pts) VALUES (old_seasonnum,player_idd,season_ptss);
    END LOOP;  

但是,我从中得到以下错误:ERROR: relation "temprow" does not exist。如果很清楚我想做什么,你能指出我正确的方法吗?

【问题讨论】:

  • 正确的做法是:“不要迭代”。您似乎可以使用纯 SQL 完全可行:insert into leaderboards(a,b,c) select x,y,z from users;
  • 正如我在答案中注意到的那样,old_seasonnum 不是从user_data.users 中选择的,而是在前一点中选择的。
  • 允许在需要表达式的地方使用常量(或变量,在 plpgsql 或准备好的语句中):insert into foo(a,b,c) select 42, y, z from bar; 注意:在您的代码中 old_seasonnum 甚至没有定义。
  • 我只是把我遇到问题的代码部分放在这里,它是在实际代码中的先前扇区中定义的。如果你觉得有必要,我会把整个代码放在这里。

标签: sql postgresql plpgsql


【解决方案1】:

一个循环遍历select并使用循环项值过滤和计算其他值的函数,

CREATE FUNCTION "UpdateTable"() RETURNS boolean
    LANGUAGE plpgsql
AS
$$
DECLARE
    TABLE_RECORD RECORD;
    BasePrice NUMERIC;
    PlatformFee NUMERIC;
    MarketPrice NUMERIC;
    FinalAmount NUMERIC;
BEGIN
    FOR TABLE_RECORD IN SELECT * FROM "SchemaName1"."TableName1" -- can select required fields only

        LOOP
            SELECT "BasePrice", "PlatformFee" INTO BasePrice, PlatformFee
            FROM "SchemaName2"."TableName2" WHERE "UserID" = TABLE_RECORD."UserRID";

            SELECT "MarketPrice" / 100 INTO MarketPrice FROM "SchemaName3"."TableName3" WHERE "DateTime" = TABLE_RECORD."DateTime";

            FinalAmount = TABLE_RECORD."Qty" * (BasePrice + PlatformFee - MarketPrice);

            UPDATE "SchemaName1"."TableName1" SET "MarketPrice" = MarketPrice, "Amount" = CFDAmount
            WHERE "ID" = CFD_RECORD."ID"; -- can update other schema tables also
        END LOOP;

    RETURN TRUE;
END
$$;

【讨论】:

    【解决方案2】:

    temprow是一个记录变量,依次绑定到第一个SELECT的每条记录。

    所以你应该写:

    FOR temprow IN
            SELECT * FROM user_data.users ORDER BY user_seasonpts DESC LIMIT 10
        LOOP
            INSERT INTO user_data.leaderboards (season_num,player_id,season_pts) VALUES (old_seasonnum,temprow.userd_id,temprow.season_ptss);
        END LOOP;
    

    这个循环可以进一步简化为一个查询:

    INSERT INTO user_data.leaderboards (season_num,player_id,season_pts)
    SELECT old_seasonnum,player_idd,season_ptss FROM user_data.users ORDER BY user_seasonpts DESC LIMIT 10
    

    【讨论】:

    • FOR/temprow 是光标吗?它会做任何锁定吗?
    • 是的,它是一个游标,但没有对 users 表进行锁定
    • 简化单查询的问题是,old_seasonnum不是从user_data.users表中选择的,而是从之前的选择中选择的,此时会用到。
    • 这是过程的局部变量吗?然后您可以将其用作SELECT old_seasonnum AS season_num ...
    • 致想知道的人,宣布 temprow RECORD;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-22
    • 2015-05-09
    • 1970-01-01
    • 2020-03-24
    • 2016-07-08
    • 2011-06-15
    • 2021-02-15
    相关资源
    最近更新 更多