仅当新数据与最新插入不同时才将新数据插入表

时间:2018-09-04 21:21:51

标签: postgresql

我想将股票价格添加到表格中-但仅当买入或卖出与上一个记录相比有所变化时。 因此,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行-应该阻止价格的第二次插入,而不是第四次。

1 个答案:

答案 0 :(得分:2)

正如您所写,唯一约束不是解决该问题的合适方法。在这种情况下,触发是一种自然的方法,例如:

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中具有相同的时间戳,因此只有在将新行插入到单独的事务中时,触发器才能正常工作。但是,我认为这种行为是合乎逻辑的并且可以接受的。

Working example in rextester.