I'm working on inventory system web app. It is based on latest Ruby on Rails and PostgreSQL. I need to track products stock values base on purchases and sales quantities. You can check out my simplified db schema (also shown below).
Table products has a stock field. This field must be calculated from products' total purchases and sales quantity.
SUM(purchases.quantity) - SUM(sales.quantity)
I'm looking for simple, performant and most important race conditions safe solution. My current (but not final) idea is to use db triggers here. But I have no mind how to implement them the right way.
CREATE TABLE products (
id INT GENERATED ALWAYS AS IDENTITY,
name varchar,
stock INT NOT NULL DEFAULT 0 CHECK (stock >= 0),
PRIMARY KEY (id)
);
CREATE TABLE purchases (
id INT GENERATED ALWAYS AS IDENTITY,
quantity INT NOT NULL DEFAULT 0,
product_id INT NOT NULL,
CONSTRAINT fk_product FOREIGN KEY (product_id) REFERENCES products (id)
);
CREATE TABLE sales (
id INT GENERATED ALWAYS AS IDENTITY,
quantity INT NOT NULL DEFAULT 0,
product_id INT NOT NULL,
CONSTRAINT fk_product FOREIGN KEY (product_id) REFERENCES products (id)
);
INSERT INTO products (name)
VALUES('Super Power');
INSERT INTO purchases (product_id, quantity)
VALUES(1, 2), (1, 3), (1, 2);
INSERT INTO sales (product_id, quantity)
VALUES(1, 1), (1, 2), (1, 2);
SELECT
*
FROM
products
Best Answer
I'm not really sure if you have much of an issue, as long as you update the
products.stock
field every time you eitherINSERT INTO
thepurchases
orsales
tables. No need for a Trigger in this scenario. Also you should ensure your update on theproducts.stock
happens in the same Transaction as yourINSERT INTO
thepurchases
andsales
tables.Alternatively you could also design your schema to not store the
stock
field on theproducts
table. Rather create a View that joinsproducts
,purchases
, andsales
together, grouped on theproduct
and aggregates the difference inpurchases
andsales
perproduct
as itsstock
, that way it's instantly always up to date whenever thepurchases
orsales
change.