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');
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;
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-side(我在这个例子中使用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;
};
});
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;
create table t (
id serial primary key,
a integer
)
;
insert into t (a)
select 2
from (
select count(*) as s
from t
where a = 2
) s
where s.s = 0
;
select id
from t
where a = 2
;
4条答案
按热度按时间pobjuy321#
Postgres 9.5或更高版本
使用“UPSERT”,以确保在多用户环境中避免可能的争用情况。请参阅:
Postgres 9.4或更早版本
单个SQL语句中的解决方案。测试设置:
INSERT
/SELECT
命令:v
不是严格必需的,但可以实现只需输入一次值的目的。s
从tbl
中选择id
。i
在tbl
中插入“行”,当(且仅当)它不存在时,返回id
。SELECT
返回id
,我添加了一列src
来指示“源”--“行”是否已经存在并且id
来自SELECT
,或者“行”是新的并且id
也是新的。tbl
的额外SELECT
,而是使用CTE。dgenwo3n2#
我建议在数据库端进行检查,并将id返回给nodejs。
示例:
然后在Node.js-side(我在这个例子中使用node-postgres):
hs1rzwqc3#
如果您使用的是PostgreSQL 9.1,则类似于此
它有点长,您需要多次重复id来进行测试,但我想不出涉及单个SQL语句的其他解决方案。
如果存在
id=42
的行,则可写CTE不会插入任何内容,因此第二个联合部分将返回现有行。在测试这个的时候,我实际上认为新行会被返回两次(因此是
union
而不是union all
),但结果是第二个select语句的结果实际上是在整个语句运行之前被求值的,它看不到新插入的行。所以如果插入了一个新行,它将从“返回”部分被取出。yebdmbv44#