如何在Postgres事务中的下一个查询中使用查询结果?

时间:2013-09-13 16:00:45

标签: sql postgresql transactions plpgsql common-table-expression

我有一个查询只有在外部引用(用户,会话)已经存在时才在数据库中插入事件。

  1. 如果用户不存在,则会插入并保存ID
  2. 如果会话不存在,则插入前一个来自用户的ID
  3. 使用先前创建的userid和sessions id插入事件。
  4. 。我收到此错误:

      

    “PHP警告:pg_query_params():查询失败:错误:语法错误   在“IF”处或附近

    此查询:

    BEGIN;
    SELECT id FROM users WHERE mongoid = $1 (userid); 
    IF not found THEN
        -- inserts user and should remember userid
        INSERT INTO users (mongoid, shopid, idinshop, attributes)
            VALUES ($1, $2, $3, $4) RETURNING id (userid);
    END IF;
    --looks for session and should remember sessionid
    SELECT id FROM sessions WHERE mongoid = $5 (sessionid);
    IF not found THEN
         -- inserts session
         INSERT INTO sessions (mongoid, shopid, userid, session, traffic, counts)
                   VALUES ($5, $2, (userid), $6, $7, $8) RETURNING id (sessionid);
    END IF;
    -- finally inserts the event
    INSERT INTO events (shopid, sessionid, userid, type, attributes, mongoid) 
         VALUES ($2, (sessionid), (userid), $9, $10, $11);
    COMMIT;
    

    稍后编辑: 我使用下面的答案解决了这个问题!

1 个答案:

答案 0 :(得分:5)

您可以使用data-modifying CTEs SQL语句中使用纯SQL 重写过程逻辑。

WITH usr1 AS (SELECT id FROM users WHERE mongoid = $1)
   , usr2 AS (
      INSERT INTO users (mongoid, shopid, idinshop, attributes)
      SELECT $1, $2, $3, $4
      WHERE  NOT EXISTS (SELECT 1 FROM usr1)
      RETURNING id
      )
   , ses1 AS (SELECT id FROM sessions WHERE mongoid = $5)
   , ses2 AS (
      INSERT INTO sessions (mongoid, shopid, userid, session, traffic, counts)
      SELECT $5, $2, (SELECT id FROM usr1 NATURAL FULL OUTER JOIN usr2
           , $6, $7, $8
      WHERE  NOT EXISTS (SELECT 1 FROM ses1)
      RETURNING id
      )
INSERT INTO events (shopid, sessionid, userid, type, attributes, mongoid) 
VALUES ($2
     , (SELECT id FROM usr1 NATURAL FULL OUTER JOIN usr2)
     , (SELECT id FROM ses1 NATURAL FULL OUTER JOIN ses2)
     , $9, $10, $11);

需要Postgres 9.1 或更高版本 未经测试。如果您想要测试答案,请在您的问题中提供测试用例。

应该比单个命令(let alone repeated round trips to the db server!)快得多。

请注意并发负载过重的潜在并发问题。提出的单个陈述已经很多不太可能导致麻烦。但可能性存在。 可能的解决方案包括manual locking(昂贵)advisory locksserializable transactions(也可能很贵)。

相关答案及更多信息:
Postgresql batch insert or ignore