Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Sinres's avatar

Table schema for product attribute

Hello,

I need to create a functionality based on assigning appropriate attributes to a product based on the product category. Exactly the point is to assign, for example, the size of the T-shirt (S, M, L) or the size of the shoe (9.5 etc.)

I have already created a database table schema but I need someone to advise if this is a good solution

My database tables:

products (ID | Properties(JSON with product name etc.) | category_id)
categories (ID | Name)
attributes( ID | Name | Type(Integer,  Numeric, String)
attribute_value ( id | attribute_id | value )
category_has_attribute(category_id | attribute_id)
product_has_attribute ( product_id | product_attributes (JSON {"size":"M", "color":"red"} )

What is worth improving? Is this a good way for this type of solution?

Thanks!

0 likes
6 replies
martinbean's avatar

@sinres Any time you use a JSON column type in a relational database like MySQL or Postgres, there’s usually a Better Way™ to model your data.

For e-commerce sites where products have variations like this, I usually model a top-level product that has the common attributes (name, description, etc) and then that product will have many SKU models. This is how a physical store will also represent those products: a pair of shoes in size 9 will have a different SKU to the same pair of shoes but in size 9.5.

So, with that said, you can extract an “attribute” model. Your can then have a pivot table between SKUs and attributes where you record the value for that SKU and attribute combination:

public function up()
{
    Schema::create('attribute_sku', function (Blueprint $table) {
        $table->primary(['attribute_id', 'sku_id']);
        $table->foreignId('attribute_id')->constrained()->cascadeOnDelete();
        $table->foreignId('sku_id')->constrained()->cascadeOnDelete();
        $table->string('value');

        $table->unique(['attribute_id', 'sku_id', 'value']);
    });
}

So you can create an attribute and set a value for it like this:

$sizeAttribute = Attribute::create([
    'name' => 'Size',
]);

$sku = Sku::find($id); // Find SKU representing shoes in size 9.5

$sku->attributes()->syncWithoutDetaching($sizeAttribute, [
    'value' => '9.5',
]);
Sinres's avatar

@martinbean Thanks for the help. I have to use JSON because my products have so many options. For example: White youth sports shoes and in this case, I have product attributes such as:

Size: 40
Type: Sports
Season: Summer
target group: Boys, girls, women, men
Color: White
Material: Leather
Internal material: Leather
Clasp type: Lace-up

And so on, it is quite difficult, especially since the basic product data is already in the database, it is a bit of a problem

You're right, I also need to create a SKU model. In addition, I want to be able to set a category when editing a product, which, when selected, will impose parameters for the product belonging to the category.

martinbean's avatar

I have to use JSON because my products have so many options.

@sinres I don’t see why this means you have to use JSON. They’re just key–value pairs. Easily representable as attributes with keys and values.

Plus, a lot of the ones in the example above probably won’t make up the SKU. I doubt for one product, you have one SKU for “season: summer” and another for “season: winter“. They just seem to be product metadata describing the product rather than the make-up of the project itself.

Sinres's avatar

@martinbean You're right. I don't think this whole relationship is quite complicated anymore.

Look at my structure now.I don't know if I implemented it correctly the SKU table here now.

Foo

Steven_MOB's avatar

@martinbean after Googling I stumbled upon this thread and I am still unsure what database design I am going to use to tackle product variations based on attributes. With the design you are describing, how would you link product variations to orders, for example? Would you store the sku in an order_products table instead of the product_id?

martinbean's avatar

@Steven_MOB Yes, a SKU would be stored, as a SKU is a specific combination of attributes for a product. A SKU unique identifies a “variant”.

Customers buy SKUs (i.e. a medium Metallica T-shirt in black). When you’ve sold every unit of medium Metallica T-shirt in black, you order more from the stockist. If you just went to your stockist and said, “can you send me more Metallica T-shirts?” they’re going to ask you, “which size and colour?”

Please or to participate in this conversation.