Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/76.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如果存在行,则返回id,否则插入_Sql_Node.js_Postgresql_Sql Insert - Fatal编程技术网

Sql 如果存在行,则返回id,否则插入

Sql 如果存在行,则返回id,否则插入,sql,node.js,postgresql,sql-insert,Sql,Node.js,Postgresql,Sql Insert,我正在node.js中编写一个函数来查询PostgreSQL表。 如果该行存在,我想从该行返回id列。 如果它不存在,我想插入它并将id插入返回到。。。返回id 我一直在尝试case和if-else语句的变体,但似乎无法使其正常工作。我建议在数据库端进行检查,并将id返回给nodejs 例如: CREATE OR REPLACE FUNCTION foo(p_param1 tableFoo.attr1%TYPE, p_param2 tableFoo.attr1%TYPE) RETURNS tab

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


我一直在尝试case和if-else语句的变体,但似乎无法使其正常工作。

我建议在数据库端进行检查,并将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;
在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;      

  };

});

如果您使用的是PostgreSQL 9.1,则类似于此

with test_insert as (
   insert into foo (id, col1, col2)
   select 42, 'Foo', 'Bar'
   where not exists (select * from foo where id = 42)
   returning foo.id, foo.col1, foo.col2
)
select id, col1, col2
from test_insert
union 
select id, col1, col2
from foo
where id = 42;
这有点长,您需要重复id进行多次测试,但我想不出一个包含单个SQL语句的不同解决方案

如果存在id=42的行,可写CTE将不插入任何内容,因此现有行将由第二个union部件返回


在测试这一点时,我实际上认为新行将返回两次,因此一个union不是union all,但事实证明,第二个select语句的结果实际上是在整个语句运行之前计算的,并且它没有看到新插入的行。因此,在插入新行的情况下,它将从返回的部分获取。

一个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');
插入/选择命令:

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;
严格来说,第一个CTE v不是必需的,但您只需输入一次值

如果行存在,则第二个CTE s从tbl中选择id

第三个CTEI将该行插入tbl,当且仅当该行不存在时,返回id

最后一个SELECT返回id。我添加了一列src,指示源-行是预先存在的,id来自SELECT,还是行是新的,id也是新的

此版本应尽可能快,因为它不需要从tbl中进行额外选择,而是使用CTE

要在多用户环境中防止可能的竞争条件,请执行以下操作: 对于使用Postgres 9.5或更高版本中新UPSERT的更新技术:


可能重复的,如果已经存在,我不想更新任何内容。我只想在这两种情况下都返回值。更新Postgres 9.5的可能副本正在获取一个功能。看,我应该提到,在开发过程中,我在Heroku上使用免费的pgsql数据库,它不允许存储过程。我可以使用node postgres在一个查询中执行此操作吗?或者我必须在一个查询中执行select操作,然后在回调中执行insert操作吗?@Jared:我可以想出一个非常难看的hack。在tid中运行查询INSERT,这是一个SELECT COALESCESELECT id,其中a=$1,nextval't_id_seq',$1是一个返回的id;如果有效,则返回id,否则将收到一个错误,即违反了主键的唯一约束。然后,您可以解析该号码的错误消息。非常难看,但实际上是可行的。我能够将Heroku上的pgsql实例升级到支持函数的公共测试版。有没有办法在任意表上使用此模式?我一直在使用类似的东西,但对N个表重复了N次。@Garen:您可以在plpgsql函数或DO语句中使用。试着找出相关的答案。是
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;