如果存在行则返回id,否则返回INSERT

Jar*_*red 10 sql postgresql node.js sql-insert

我正在node.js中编写一个函数来查询PostgreSQL表.
如果该行存在,我想从该行返回id列.
如果它不存在,我想插入它并返回id(insert into ... returning id).

我一直在尝试变体caseif else语句,似乎无法让它发挥作用.

Erw*_*ter 10

单个SQL语句中的解决方案.但需要PostgreSQL 8.4或更高版本.
请考虑以下演示:

测试设置:

CREATE TEMP TABLE tbl (
  id  serial PRIMARY KEY
 ,txt text   UNIQUE   -- obviously there is unique column (or set of columns)
);

INSERT INTO tbl(txt) VALUES ('one'), ('two');
Run Code Online (Sandbox Code Playgroud)

INSERT/SELECT命令:

WITH v AS (SELECT 'three'::text AS txt)
    ,s AS (SELECT id FROM tbl JOIN v USING (txt))
    ,i AS (
       INSERT INTO tbl (txt)
       SELECT txt
       FROM   v
       WHERE  NOT EXISTS (SELECT * FROM s)
       RETURNING id
       )
SELECT id, 'i'::text AS src FROM i
UNION  ALL
SELECT id, 's' FROM s;
Run Code Online (Sandbox Code Playgroud)
  • 第一个CTE v并非绝对必要,但要实现您只需输入一次.

  • 第二CTE S选用idtbl如果"行"的存在.

  • 第三个 CTE我将 "行"插入tblif(并且仅当它)不存在时返回id.

  • 决赛SELECT归来了id.我添加了一个src指示"源" 的列- "行"是否预先存在并id来自SELECT,或者"行"是新的,因此是id.

  • 此版本应尽可能快,因为它不需要额外的SELECT,tbl而是使用CTE.

为了在多用户环境中保护其免受可能的竞争条件的影响:
对于在Postgres 9.5或更高版本中使用新UPSERT的更新技术:


Mar*_*her 8

我建议在数据库端进行检查,然后将id返回给nodejs.

例:

CREATE OR REPLACE FUNCTION foo(p_param1 tableFoo.attr1%TYPE, p_param2 tableFoo.attr1%TYPE) RETURNS tableFoo.id%TYPE AS $$
  DECLARE
  v_id tableFoo.pk%TYPE;
  BEGIN
    SELECT id
    INTO v_id
    FROM tableFoo
    WHERE attr1 = p_param1
    AND attr2 = p_param2;

    IF v_id IS NULL THEN
      INSERT INTO tableFoo(id, attr1, attr2) VALUES (DEFAULT, p_param1, p_param2)
      RETURNING id INTO v_id;
    END IF;

    RETURN v_id:

  END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

而不是在Node.js端(我在这个例子中使用node-postgres):

var pg = require('pg');
pg.connect('someConnectionString', function(connErr, client){

  //do some errorchecking here

  client.query('SELECT id FROM foo($1, $2);', ['foo', 'bar'], function(queryErr, result){

    //errorchecking

    var id = result.rows[0].id;      

  };

});
Run Code Online (Sandbox Code Playgroud)