3

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

  1. 如果用户不存在,它会被插入并且应该保存 id
  2. 如果会话不存在,则使用用户先前的 id 插入它
  3. 使用先前创建的用户 ID 和会话 ID 插入事件。

.我得到这个错误:

“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;

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

4

1 回答 1

7

您可以使用数据修改 CTE单个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或更高版本。
未经测试。如果您想要经过测试的答案,请在您的问题中提供一个测试用例。

应该比单个命令快得多(更不用说重复往返数据库服务器了!)。

请注意高并发负载的潜在并发问题。提出的单一声明已经不太可能引起麻烦。但可能性是存在的。可能的解决方案包括手动锁定(昂贵的)咨询锁可序列化事务(也可能很昂贵)。

包含更多信息的相关答案:
Postgresql 批量插入或忽略

于 2013-09-13T17:27:08.847 回答