You have a basic product table. In this table you can get the base price of the product.
You have a base table ATTRIBUTES. Just a list of possible attributes that can be applied to your products. This is usually more complicated than a simple list, i.e. Usually it is also tied to the type of product. In other words, not all attributes apply to all products. Therefore, some systems also have a PRODUCTTYPE table and a PRODUCTTYPEATTRIBUTES table. And some attributes are only applicable if other attributes are valid. See the example below. There it can become very difficult.
You have a link table in which PRODUCT is connected to one or more ATTRIBUTES. In this table, the price of adding the attribute is added.
Cost of a product is its base price plus the sum of the prices of its attribute (s). Chair = 100. Leather = 75. Brass tacks = 25 update. Leather chair with brass pads = 200. But you do not need brass tips if you do not have a leather upgrade. So stool + brass is not a real option. Some databases apply such rules in their structure. Others do this in an interface. It can get quite complicated.
But this three-table structure allows you to have multiple attributes for each product. A customer can order a base product or a base product with one or more attributes associated with the product in your PRODUCTATTRIBUTES table.
The unique composite indexes in the PRODUCTATTRIBUTES table (productid, attributeid) will not allow the user to apply the attribute more than once: chair + leather + leather + brass plates will not be possible, and therefore you also prevent the user from updating the skin costs 100 in one row and 125 in another, for the same product.
source share