Вставить записи на основе последней записи внешней таблицы - PullRequest
0 голосов
/ 27 мая 2018

У меня есть следующие простые табличные отношения:

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, конвертированное из перечисления Java, может быть: ИНИЦИАЛИЗИРОВАНО, ДОСТУПНО, ОБРАБОТАНО и т. Д.

Я хочу сделать следующее: если в последней записи события продукта указано STATE 'PROCESSED', то создайте новую вставку в таблице EVENT со значением STATE 'AVAILABLE'.Это должно быть для всех продуктов.

Как видите, в таблице событий есть ссылка на товар.Я смотрел на: Вставить, при дублировании обновления в PostgreSQL?

Но не мог понять это.

Ответы [ 2 ]

0 голосов
/ 27 мая 2018

Если ваши данные вставляются последовательно, я бы более склонен использовать 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 поддерживает поддерживаемых перечисляемых типов , и у вас его нет.Однако то, что вы хотите сделать, часто обрабатывается с помощью проверочного ограничения:

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'))
);
0 голосов
/ 27 мая 2018
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;
...