Вставлять новые данные в таблицу, только если они отличаются от последней вставки - PullRequest
0 голосов
/ 05 сентября 2018

Я хочу добавить цены акций в таблицу - но только если покупка или продажа изменились по сравнению с последней записью. Поэтому UNIQUE на самом деле не работает, так как не позволяет использовать одну и ту же ценовую комбинацию в таблице более одного раза. Я могу придумать пути решения проблемы за пределами postgres (до фактической вставки строк), но мне было интересно, есть ли способ настроить таблицу цен , чтобы справиться с этим для меня.

CREATE TABLE stock(
    id SMALLSERIAL PRIMARY KEY,
    name VARCHAR(3) UNIQUE NOT NULL
);

CREATE TABLE prices(
    id SMALLSERIAL PRIMARY KEY,
    created_at TIMESTAMPTZ DEFAULT current_timestamp,
    stock_id INTEGER NOT NULL,
    buy NUMERIC(15, 6) NOT NULL,
    sell NUMERIC(15, 6) NOT NULL,
    FOREIGN KEY (stock_id) REFERENCES stock(id),
    UNIQUE(stock_id, buy, sell) 
);


INSERT INTO stock(name) VALUES('abc');
INSERT INTO prices (stock_id, buy, sell) VALUES (1, 1.5, 1.4) 
ON CONFLICT (stock_id, buy, sell) DO NOTHING;
INSERT INTO prices (stock_id, buy, sell) VALUES (1, 1.5, 1.4) 
ON CONFLICT (stock_id, buy, sell) DO NOTHING; -- this record should not be added to the table
INSERT INTO prices (stock_id, buy, sell) VALUES (1, 1.6, 1.5) 
ON CONFLICT (stock_id, buy, sell) DO NOTHING;
INSERT INTO prices (stock_id, buy, sell) VALUES (1, 1.5, 1.4) 
ON CONFLICT (stock_id, buy, sell) DO NOTHING; -- this one should be added to the table

sqlfiddle

Так что в моем примере я хотел бы иметь 3 строки в таблице вместо 2 - должна блокироваться только 2-я вставка в цены, а не 4-я.

1 Ответ

0 голосов
/ 05 сентября 2018

Как вы писали, уникальное ограничение не является подходящим решением проблемы. Триггер - это естественный подход в таких случаях, например:

create or replace function before_insert_on_prices()
returns trigger language plpgsql as $$
declare
    last_rec record;
begin
    select buy, sell
    from prices
    where stock_id = new.stock_id
    order by created_at desc
    limit 1
    into last_rec;

    if found and last_rec = (new.buy, new.sell) then
        return null;
    end if;
    return new;
end $$;

create trigger before_insert_on_prices
before insert on prices
for each row execute procedure before_insert_on_prices();

Обратите внимание, что триггер будет работать хорошо только тогда, когда новые строки вставляются в отдельные транзакции, поскольку несколько строк, вставленных в одну транзакцию, будут иметь одинаковую метку времени в created_at. Однако это поведение вполне логично и приемлемо, я думаю.

Рабочий пример в rextester.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...