带有特定子句的 upsert postgresql
upsert with spesific clause postgresql
我需要一些关于在 postgres 中更新插入的帮助
例如,我有一个 table 结构,如:
CREATE TABLE users_recency(
id INTEGER PRIMARY KEY,
created_date TIMESTAMP WITHOUT TIME ZONE,
first_transaction TIMESTAMP WITHOUT TIME ZONE
)
CREATE TABLE users_transaction(
id INTEGER,
users_id INTEGER,
transaction_date TIMESTAMP WITHOUT TIME ZONE
)
如果 users_id 不存在于用户数据库中,我想做的是插入新用户,然后如果 users_transaction.transaction_date < users_recency.first_transaction.[= 更新 first_transaction 13=]
我尝试使用
INSERT INTO users_recency(id, first_transaction)
SELECT users_id, MIN(transaction_date) FROM users_transaction GROUP BY users_id
ON CONFLICT (id)
DO
UPDATE SET first_transaction = EXCLUDED.first_transaction;
此查询更新了所有数据。有什么办法可以实现吗?
这里有一个数据库 fiddle 可以试试
您的查询缺少 WHERE
条件,该条件将限制 first_transaction 的修改,以防它小于 transaction_date 值。
更新查询:
INSERT INTO users_recency(id, first_transaction)
SELECT users_id, MIN(transaction_date) FROM users_transaction GROUP BY users_id
ON CONFLICT (id)
DO
UPDATE SET first_transaction = EXCLUDED.first_transaction
WHERE EXCLUDED.first_transaction < users_recency.first_transaction;
db fiddle link 为了更好地理解:
https://dbfiddle.uk/?rdbms=postgres_14&fiddle=a8d6b6601424006219dbec5db47817c9
一般Insert
语法:
[ WITH [ RECURSIVE ] with_query [, ...] ]
INSERT INTO table_name [ AS alias ] [ ( column_name [, ...] ) ]
[ OVERRIDING { SYSTEM | USER } VALUE ]
{ DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }
[ ON CONFLICT [ conflict_target ] conflict_action ]
[ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]
where conflict_target can be one of:
( { index_column_name | ( index_expression ) } [ COLLATE collation ] [ opclass ] [, ...] ) [ WHERE index_predicate ]
ON CONSTRAINT constraint_name
and conflict_action is one of:
DO NOTHING
DO UPDATE SET { column_name = { expression | DEFAULT } |
( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) |
( column_name [, ...] ) = ( sub-SELECT )
} [, ...]
[ WHERE condition ]
有关 Insert
的更多信息,请查看以下官方文档 link:
通过触发器。
demo
CREATE OR REPLACE FUNCTION users_txn_trg_func ()
RETURNS TRIGGER
AS $$
DECLARE
min_tx_date date;
BEGIN
IF EXISTS (
SELECT
FROM
users_transaction u
WHERE
u.users_id = NEW.users_id) THEN
SELECT
min(transaction_date) INTO min_tx_date
FROM
users_transaction
WHERE
users_id = NEW.users_id;
IF NEW.transaction_date < min_tx_date THEN
min_tx_date := NEW.transaction_date;
END IF;
RAISE info 'new user_id: %, min_tx_date: %', NEW.users_id, min_tx_date;
ELSE
min_tx_date := NEW.transaction_date;
RAISE NOTICE 'min_tx_date: %', min_tx_date;
END IF;
INSERT INTO users_recency (id, first_transaction)
VALUES (NEW.users_id, min_tx_date)
ON CONFLICT (id)
DO UPDATE SET
first_transaction = EXCLUDED.first_transaction;
RETURN new;
END;
$$
LANGUAGE plpgsql;
CREATE TRIGGER trigger_name
BEFORE INSERT ON users_transaction FOR EACH ROW
EXECUTE PROCEDURE users_txn_trg_func ();
我需要一些关于在 postgres 中更新插入的帮助
例如,我有一个 table 结构,如:
CREATE TABLE users_recency(
id INTEGER PRIMARY KEY,
created_date TIMESTAMP WITHOUT TIME ZONE,
first_transaction TIMESTAMP WITHOUT TIME ZONE
)
CREATE TABLE users_transaction(
id INTEGER,
users_id INTEGER,
transaction_date TIMESTAMP WITHOUT TIME ZONE
)
如果 users_id 不存在于用户数据库中,我想做的是插入新用户,然后如果 users_transaction.transaction_date < users_recency.first_transaction.[= 更新 first_transaction 13=]
我尝试使用
INSERT INTO users_recency(id, first_transaction)
SELECT users_id, MIN(transaction_date) FROM users_transaction GROUP BY users_id
ON CONFLICT (id)
DO
UPDATE SET first_transaction = EXCLUDED.first_transaction;
此查询更新了所有数据。有什么办法可以实现吗?
这里有一个数据库 fiddle 可以试试
您的查询缺少 WHERE
条件,该条件将限制 first_transaction 的修改,以防它小于 transaction_date 值。
更新查询:
INSERT INTO users_recency(id, first_transaction)
SELECT users_id, MIN(transaction_date) FROM users_transaction GROUP BY users_id
ON CONFLICT (id)
DO
UPDATE SET first_transaction = EXCLUDED.first_transaction
WHERE EXCLUDED.first_transaction < users_recency.first_transaction;
db fiddle link 为了更好地理解:
https://dbfiddle.uk/?rdbms=postgres_14&fiddle=a8d6b6601424006219dbec5db47817c9
一般Insert
语法:
[ WITH [ RECURSIVE ] with_query [, ...] ]
INSERT INTO table_name [ AS alias ] [ ( column_name [, ...] ) ]
[ OVERRIDING { SYSTEM | USER } VALUE ]
{ DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }
[ ON CONFLICT [ conflict_target ] conflict_action ]
[ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]
where conflict_target can be one of:
( { index_column_name | ( index_expression ) } [ COLLATE collation ] [ opclass ] [, ...] ) [ WHERE index_predicate ]
ON CONSTRAINT constraint_name
and conflict_action is one of:
DO NOTHING
DO UPDATE SET { column_name = { expression | DEFAULT } |
( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) |
( column_name [, ...] ) = ( sub-SELECT )
} [, ...]
[ WHERE condition ]
有关 Insert
的更多信息,请查看以下官方文档 link:
通过触发器。 demo
CREATE OR REPLACE FUNCTION users_txn_trg_func ()
RETURNS TRIGGER
AS $$
DECLARE
min_tx_date date;
BEGIN
IF EXISTS (
SELECT
FROM
users_transaction u
WHERE
u.users_id = NEW.users_id) THEN
SELECT
min(transaction_date) INTO min_tx_date
FROM
users_transaction
WHERE
users_id = NEW.users_id;
IF NEW.transaction_date < min_tx_date THEN
min_tx_date := NEW.transaction_date;
END IF;
RAISE info 'new user_id: %, min_tx_date: %', NEW.users_id, min_tx_date;
ELSE
min_tx_date := NEW.transaction_date;
RAISE NOTICE 'min_tx_date: %', min_tx_date;
END IF;
INSERT INTO users_recency (id, first_transaction)
VALUES (NEW.users_id, min_tx_date)
ON CONFLICT (id)
DO UPDATE SET
first_transaction = EXCLUDED.first_transaction;
RETURN new;
END;
$$
LANGUAGE plpgsql;
CREATE TRIGGER trigger_name
BEFORE INSERT ON users_transaction FOR EACH ROW
EXECUTE PROCEDURE users_txn_trg_func ();