问题
Virtually all POS systems record the price of an item directly to the transactions table at the time of the sale since that price may change at a later date, but the price it sold at should remain the same.
I'm wondering how you would setup pricing table(s) that keep a history of price changes, so that you can relate the transactions to that table based on the item and the time it was sold in order to get the correct price?
I think anyone who's ever worked with POS systems will understand what I'm talking about here, but if my question is unclear let me know and I will try to explain better.
I didn't tag a specific database because this question obviously isn't specific to a particular one, but because I know it's the first question I'll be asked: SQL Server 2008.
EDIT:
Here's one solution I just thought of that I would love to get some feedback on...
I'm thinking I could have a price table that has fields like so: PriceId, ItemId, Price, Date
PriceId would be an autonumber and ItemId relates to the Items table. Now instead of saving the actual price to the transactions table, I would save the most current PriceId for the given item.
Thoughts?
回答1:
I don't really see a reason for doing this. You're adding an extra join for almost all analytic purposes and most queries, which will impact the speed of the application.
Answering your question though the easiest thing would be to create your pricing tables as if you were creating a temporal database.
So, making a few assumptions, your pricing table might have the columns:
id int, pk
product_id, fk into products
price_start_date date
price_end_date date
price number(x, 2)
Assuming your "orders" table has the date that the order was placed on / posted etc, whatever you use to determine price every query to determine price would become
select price
from pricing p
join orders o
on o.order_Date between p.price_start_date and p.price_end_date
However, as I say I would not do this. The only hindrance, that I can think of, to having historical prices in the orders table as opposed to a separate one is that it makes historical prices analyses slightly heavier on the DB. You're not going to do this very often without also wanting to know how many units are sold and thus needing to use the orders table anyway so I don't think it makes a big difference.
I think this is one of those occurrences where a very slightly denormalised database is definitely a positive rather than a negative.
Okay, regarding your edit there is very little difference to what I have suggested. I'm going to assume that your table is unique on itemid
and date
(don't use this as the actual column name) otherwise the date could be held equally well in your "items" table.
However, it does mean that whenever you add something to the transactions table you have to use an aggregate query to work out the most recent price for each item. My suggestion makes updating a price more difficult but working out the price easier. As you calculate the price of an item more regularly than you update a price I'd, personally, take the performance hit where I've suggested.
回答2:
I faced this problem on my last project and I decided to go use a prices table to keep the historical prices because the client wanted to verify how often his providers where changing the price etc. For many reports I found myself making an extra join just to retrieve the current price which felt a lot cumbersome, so I ended up with a table like this.
product:
name ...
quantity ...
...
priceId ... (foreign key to lastest price on prices table)
price ... (the last updated price, to avoid the prices join)
回答3:
You'd have to adapt this to your situation, but in mine, I had a lookup table of charge types, and this was how I updated the charge to a new price and retained the original price for reference. The overhead of the view in this is only in terms of however often you query it for generating an invoice. Which is my use case.
You use vwCharge here to get a list of the most current pricing. When update_charge_rate() is used, it adds a new one with the date it was updated, and querying vwCharge will only show the most recent.
The delimiter is set to //
The lookup table:
CREATE TABLE lkCharge (
charge_id SMALLINT NOT NULL AUTO_INCREMENT,
charge_datecreated DATE NOT NULL,
charge_name VARCHAR(20) NOT NULL,
charge_rate DECIMAL(10,2) NOT NULL,
charge_islocked CHAR(1) DEFAULT 'N',
charge_lockedby VARCHAR(255) DEFAULT NULL,
charge_lockdate TIMESTAMP NULL,
charge_isdeleted CHAR(1) DEFAULT 'N',
CONSTRAINT pkChargeId PRIMARY KEY(charge_id, charge_datecreated)
) ENGINE=InnoDB DEFAULT CHARSET=utf8//
The view:
CREATE VIEW vwCharge AS
SELECT
charge_id,
charge_datecreated,
charge_name,
charge_rate,
charge_islocked,
charge_lockedby,
charge_lockdate,
charge_isdeleted
FROM lkCharge AS o
WHERE o.charge_id=o.charge_id AND charge_datecreated=(
SELECT MAX(charge_datecreated)
FROM lkCharge AS i
WHERE i.charge_id=o.charge_id
)//
The update procedure:
CREATE PROCEDURE update_charge_rate(
IN p_charge_id SMALLINT,
IN p_new_charge_rate DECIMAL(10,2)
)
BEGIN
DECLARE _name VARCHAR(20);
SELECT charge_name INTO _name
FROM vwCharge WHERE charge_id=p_charge_id;
INSERT INTO lkCharge(charge_id, charge_datecreated, charge_name, charge_rate)
VALUES(p_charge_id, UTC_DATE(), _name, p_new_charge_rate);
SELECT LAST_INSERT_ID();
END//
来源:https://stackoverflow.com/questions/11818965/how-to-properly-relate-items-to-pricing-data-taking-price-change-history-into-a