我有以下简单的表关系:
Expression.Call
" STATE"在Event中,从Java Enum转换,可以是:INITIALIZED,AVAILABLE,PROCESSED等。
我想执行以下操作:如果产品的最后一个事件条目具有STATE' PROCESSED',则在EVENT表中创建一个新的插入,其中STATE' AVAILABLE'。这必须适用于所有产品。
如您所见,事件表中包含对产品的引用。我查看了:Insert, on duplicate update in PostgreSQL?
但无法理解。
答案 0 :(得分:1)
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
);
如果此命令应该在多线程/多用户环境中运行,那么整个事务必须包含这四个命令,否则可能会出现重复记录:
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;
答案 1 :(得分:1)
如果按顺序插入数据,我会更倾向于使用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'))
);