我正在尝试将Oracle合并查询迁移到PostgreSql。正如this文章中所述,Postgres UPSERT语法支持" where子句"确定冲突条件。
不幸的是,该网页没有提供" where子句"的示例。我尝试在其他地方寻找它但却找不到它。因此这个问题。
按照上面给出的网页中的相同示例,这是一个示例设置:
CREATE TABLE customers (
customer_id serial PRIMARY KEY,
name VARCHAR UNIQUE,
email VARCHAR NOT NULL,
active bool NOT NULL DEFAULT TRUE
);
INSERT INTO customers (NAME, email) VALUES
('IBM', 'contact@ibm.com'),
('Microsoft', 'contact@microsoft.com'),
('Intel','contact@intel.com');
SELECT * FROM customers;
customer_id | name | email | active
-------------+-----------+-----------------------+--------
1 | IBM | contact@ibm.com | t
2 | Microsoft | contact@microsoft.com | t
3 | Intel | contact@intel.com | t
(3 rows)
我希望我的UPSERT语句看起来像这样:
INSERT INTO customers (NAME, email)
VALUES
('Microsoft', 'hotline@microsoft.com')
ON CONFLICT where (name = 'Microsoft' and active = TRUE)
DO UPDATE SET email = 'hotline@microsoft.com';
这个例子有点做作,但我希望我能在这里传达这个要点。
答案 0 :(得分:5)
您需要部分索引。删除列name
上的uniqe约束并在列上创建部分索引:
CREATE TABLE customers (
customer_id serial PRIMARY KEY,
name VARCHAR,
email VARCHAR NOT NULL,
active bool NOT NULL DEFAULT TRUE
);
CREATE UNIQUE INDEX ON customers (name) WHERE active;
INSERT INTO customers (NAME, email) VALUES
('IBM', 'contact@ibm.com'),
('Microsoft', 'contact@microsoft.com'),
('Intel','contact@intel.com');
查询应如下所示:
INSERT INTO customers (name, email)
VALUES
('Microsoft', 'hotline@microsoft.com')
ON CONFLICT (name) WHERE active
DO UPDATE SET email = excluded.email;
SELECT *
FROM customers;
customer_id | name | email | active
-------------+-----------+-----------------------+--------
1 | IBM | contact@ibm.com | t
3 | Intel | contact@intel.com | t
2 | Microsoft | hotline@microsoft.com | t
(3 rows)
请注意正确使用特殊记录excluded.
Per the documentation:
ON CONFLICT DO UPDATE中的SET和WHERE子句可以使用表的名称(或别名)访问现有行,并使用特殊的排除表访问建议插入的行。