PostgreSQL中的游标循环

4

以下是PostgreSQL 9.0中的游标代码。我想通过连接多个表来获取记录,并从该连接中获取JSON数据。

所以我想循环这些记录并使用类似查询的方式解析那个json

SELECT "Dump"->'activities-steps'->0->'value' as "steps"
FROM "ActivitySessionDump" where "Id"=42594321345021288   

然后我需要从这个查询中获取数据并插入到其他表格中,例如:
insert to table name (key,value);

所以我准备了一个只读游标来完成这个任务。
begin work;

DECLARE 
sessionids INSENSITIVE no scroll CURSOR FOR 
SELECT asn."Id",asn."UserId",asn."ActivityId",ad."Dump"
  FROM "ActivitySession" as asn inner join "ActivitySessionDump" as ad 
  on asn."Id"=ad."ActivitySessionId" 
  where asn."CreatedAt" between now() - interval '5 hours' and now() and asn."ActivityId"=1 
for read only;
---- i want her loop should start and i will parse a json Dump by executing query--------

--------insert record to another table---------------

---end loop-----------
FETCH next FROM sessionids;
CLOSE sessionids;
COMMIT WORK;

任何帮助都非常感激。谢谢。

你的问题是什么?请发布你的函数的完整源代码。 - user330315
在我的代码中,我添加了一些注释,即我想在游标声明后开始一个循环,并执行一个 SQL 并插入到某个表中。 - deadpool
我还没有创建任何函数,我只想创建一个游标。 - deadpool
谢谢,我们会的。但是能帮我怎么实现吗?这里真的需要函数吗? - deadpool
通过函数和游标的帮助,如何完成这个任务。 - deadpool
显示剩余2条评论
3个回答

1

由于SQL不能循环,您需要使用PL/pgSQL,例如使用DO语句。

在您的情况下,可能会像这样:

DO
$$DECLARE
   asn_id ...;
   asn_userid ...;
   ...
   c refcursor;
BEGIN
   /* assign the SQL cursor to the refcursor variable */
   c := 'sessionids';

   LOOP
      FETCH c INTO asn_id, asn_userid, ...;
      IF NOT FOUND THEN EXIT; END IF;

      /* process the result row */

   END LOOP;
END;$$;

当然,在SQL中声明游标并在PL/pgSQL中使用它有点笨拙。像这样将语句放入FOR循环中可能更好:
FOR asn_id, asn_userid, ... IN
  SELECT ...
LOOP

   /* process the result row */

END LOOP;

也许你甚至可以把整个过程压缩到一个单一的INSERT语句中,这将是最有效的:
INSERT INTO ...
   (SELECT ...);

非常感谢您的建议,但我已经让我的代码运行起来了。 - deadpool

1

这是我问题的代码,我无法执行:EXECUTE 'SELECT rec."Dump"::json#>''{activities-steps,0}''->>''value'' as steps ' INTO jsonrec; line;

而这段代码可以在控制台中执行:SELECT '{"activities-steps":[{"dateTime":"2016-10-17","value":"4023"}]}'::json#>'{activities-steps,0}'->>'value' as steps;

但在函数内部却无法执行。

CREATE OR REPLACE FUNCTION ThirdPartyDataParse()
RETURNS text AS $$
DECLARE 
sessionid NO SCROLL CURSOR FOR SELECT asn."Id",asn."UserId",asn."ActivityId",pd."DataSourceId",ad."Dump"::TEXT
   FROM "Development"."ActivitySession" as asn inner join "Development"."PersonDataSource" as pd on pd."UserId" = asn."UserId" inner join "Development"."ActivitySessionDump" as ad 
   on asn."Id"=ad."ActivitySessionId" where asn."CreatedAt" between now() - interval '5 days' and now() and asn."ActivityId"=1  and pd."DataSourceId"=1 for read only;
titles TEXT DEFAULT '';
rec record;
jsonrec record;
 BEGIN
 OPEN sessionid;
loop

FETCH sessionid INTO rec;
--raise notice '%d',rec."UserId";
   if not found then
        exit ;
   end if;
 EXECUTE 'SELECT rec."Dump"::json#>''{activities-steps,0}''->>''value'' as steps ' INTO jsonrec;
titles := titles || ',' || jsonrec."steps";
end loop;
return titles;
END;
$$ LANGUAGE plpgsql;

你不需要循环来实现这个。整个函数可以用一个简单的SELECT语句替代。 - user330315
我需要在执行那个 SQL 语句(SELECT "Dump"->''activities-steps''->0->''value'')之前检查一些内容,然后将结果插入到某个地方。 - deadpool
如果您想要插入结果,请使用 insert into ... select ...。而且您的函数在执行之前不会进行任何“检查”。如果该检查无法作为 where 条件集成到 SELECT 语句中,我也不会感到惊讶。 - user330315
你好,你能帮忙吗?链接 - deadpool

1
据我所知,循环或函数是不必要的。可以使用字符串聚合来替换它,进行简单的查询:
SELECT string_agg("Dump"->'activities-steps'->0->'value', ',') as steps 
FROM "ActivitySessionDump" d
WHERE d."ActivitySessionId" IN (SELECT asn."Id"
                                FROM "ActivitySession" as asn 
                                  join "PersonDataSource" as pd on pd."UserId" = asn."UserId" 
                                where asn."CreatedAt" between now() - interval '5 days' and now() 
                                  and asn."ActivityId" = 1  
                                  and pd."DataSourceId" = 1);

虽然与此无关,但是:您应该真的避免使用那些可怕的引用标识符。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接