根据外国的最后一个条目插入记录 table
Insert records based on last entry of foreign table
我有以下简单的 table 关系:
CREATE TABLE PRODUCT (
ID BIGSERIAL,
TYPE VARCHAR(24),
TITLE VARCHAR(128),
PRIMARY KEY (ID)
);
CREATE TABLE EVENT (
ID BIGSERIAL,
STATE VARCHAR(64) NOT NULL,
DATETIME TIMESTAMP NOT NULL,
PRODUCT_ID BIGINT,
FOREIGN KEY (PRODUCT_ID) REFERENCES PRODUCT(ID),
PRIMARY KEY (ID)
);
Event中的"STATE",是由Java枚举转换而来,可以是:INITIALIZED、AVAILABLE、PROCESSED等
我想执行以下操作:如果产品的最后一个事件条目具有状态 'PROCESSED',则在具有状态 'AVAILABLE' 的事件 table 中创建一个新插入。这必须适用于所有产品。
如您所见,事件 table 引用了产品。我看过:Insert, on duplicate update in PostgreSQL?
但是想不通
INSERT INTO EVENT( STATE, DATETIME, PRODUCT_ID )
SELECT 'AVAILABLE', current_timestamp, product_id
FROM EVENT e
WHERE PRODUCT_ID = 123
AND e.STATE = 'PROCESSED'
AND NOT EXISTS (
SELECT 'anything' FROM event e1
WHERE e1.PRODUCT_ID = e.PRODUCT_ID
AND e1.DATETIME > e.DATETIME
);
如果这条命令要在multithread/multiuser环境下运行,那么整个交易必须由这四个命令组成,否则可能会出现重复记录:
BEGIN TRANSACTION;
/* lock the parent record */
PERFORM id FROM PRODUCT WHERE id = 123 FOR UPDATE;
INSERT INTO EVENT( STATE, DATETIME, PRODUCT_ID )
SELECT 'AVAILABLE', current_timestamp, product_id
FROM EVENT e
WHERE PRODUCT_ID = 123
AND e.STATE = 'PROCESSED'
AND NOT EXISTS (
SELECT 'anything' FROM event e1
WHERE e1.PRODUCT_ID = e.PRODUCT_ID
AND e1.DATETIME > e.DATETIME
);
COMMIT;
如果您的数据是按顺序插入的,我更倾向于使用 id
进行比较,如:
insert into event (state, datetime, product_id)
select 'AVAILABLE', current_timestamp, product_id
from event e
where e.state = 'PROCESSED' and
not exists (select e2.state
from event e2
where e2.product_id = e.product_id and
e2.id > e.id -- you can use timestamp
);
我更感兴趣的是你说state
是一个enum
。 Postgres 支持 enumerated types,而您没有。然而,你想做的事情通常使用检查约束来处理:
CREATE TABLE EVENT (
ID BIGSERIAL,
STATE VARCHAR(64) NOT NULL,
DATETIME TIMESTAMP NOT NULL,
PRODUCT_ID BIGINT,
FOREIGN KEY (PRODUCT_ID) REFERENCES PRODUCT(ID),
PRIMARY KEY (ID),
CONSTRAINT CHECK_EVENT_STATE CHECK (STATE IN ('INITIALIZED', 'AVAILABLE', 'PROCESSED'))
);
我有以下简单的 table 关系:
CREATE TABLE PRODUCT (
ID BIGSERIAL,
TYPE VARCHAR(24),
TITLE VARCHAR(128),
PRIMARY KEY (ID)
);
CREATE TABLE EVENT (
ID BIGSERIAL,
STATE VARCHAR(64) NOT NULL,
DATETIME TIMESTAMP NOT NULL,
PRODUCT_ID BIGINT,
FOREIGN KEY (PRODUCT_ID) REFERENCES PRODUCT(ID),
PRIMARY KEY (ID)
);
Event中的"STATE",是由Java枚举转换而来,可以是:INITIALIZED、AVAILABLE、PROCESSED等
我想执行以下操作:如果产品的最后一个事件条目具有状态 'PROCESSED',则在具有状态 'AVAILABLE' 的事件 table 中创建一个新插入。这必须适用于所有产品。
如您所见,事件 table 引用了产品。我看过:Insert, on duplicate update in PostgreSQL?
但是想不通
INSERT INTO EVENT( STATE, DATETIME, PRODUCT_ID )
SELECT 'AVAILABLE', current_timestamp, product_id
FROM EVENT e
WHERE PRODUCT_ID = 123
AND e.STATE = 'PROCESSED'
AND NOT EXISTS (
SELECT 'anything' FROM event e1
WHERE e1.PRODUCT_ID = e.PRODUCT_ID
AND e1.DATETIME > e.DATETIME
);
如果这条命令要在multithread/multiuser环境下运行,那么整个交易必须由这四个命令组成,否则可能会出现重复记录:
BEGIN TRANSACTION;
/* lock the parent record */
PERFORM id FROM PRODUCT WHERE id = 123 FOR UPDATE;
INSERT INTO EVENT( STATE, DATETIME, PRODUCT_ID )
SELECT 'AVAILABLE', current_timestamp, product_id
FROM EVENT e
WHERE PRODUCT_ID = 123
AND e.STATE = 'PROCESSED'
AND NOT EXISTS (
SELECT 'anything' FROM event e1
WHERE e1.PRODUCT_ID = e.PRODUCT_ID
AND e1.DATETIME > e.DATETIME
);
COMMIT;
如果您的数据是按顺序插入的,我更倾向于使用 id
进行比较,如:
insert into event (state, datetime, product_id)
select 'AVAILABLE', current_timestamp, product_id
from event e
where e.state = 'PROCESSED' and
not exists (select e2.state
from event e2
where e2.product_id = e.product_id and
e2.id > e.id -- you can use timestamp
);
我更感兴趣的是你说state
是一个enum
。 Postgres 支持 enumerated types,而您没有。然而,你想做的事情通常使用检查约束来处理:
CREATE TABLE EVENT (
ID BIGSERIAL,
STATE VARCHAR(64) NOT NULL,
DATETIME TIMESTAMP NOT NULL,
PRODUCT_ID BIGINT,
FOREIGN KEY (PRODUCT_ID) REFERENCES PRODUCT(ID),
PRIMARY KEY (ID),
CONSTRAINT CHECK_EVENT_STATE CHECK (STATE IN ('INITIALIZED', 'AVAILABLE', 'PROCESSED'))
);