How to properly relate items to pricing data, taking price change history into account

时光总嘲笑我的痴心妄想 提交于 2019-12-04 11:04:36

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.

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)

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//
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!