web-dev-qa-db-ja.com

多対多の関係(製品のバリエーション)の組み合わせのためのSQLスキーマの設計

タイトルが参考になれば幸いです。データベースとしてMySQLを使用しています

私は製品のデータベースを構築していますが、製品のバリエーションの価格/ SKUの保存をどのように処理するかわかりません。商品には無制限のバリエーションがあり、バリエーションの組み合わせごとに独自の価格/ SKUなどがあります。

これが、現時点で製品/バリエーションのテーブルを設定する方法です。

PRODUCTS
+--------------------------+
| id | name | description  |
+----+------+--------------+
| 1  | rug  | a cool rug   |
| 2  | cup  | a coffee cup |
+----+------+--------------+

PRODUCT_VARIANTS
+----+------------+----------+-----------+
| id | product_id | variant  | value     |
+----+------------+----------+-----------+
| 1  | 1          | color    | red       |
| 2  | 1          | color    | blue      |
| 3  | 1          | color    | green     |
| 4  | 1          | material | wool      |
| 5  | 1          | material | polyester |
| 6  | 2          | size     | small     |
| 7  | 2          | size     | medium    |
| 8  | 2          | size     | large     |
+----+------------+----------+-----------+

(`products.id` is a foreign key of `product_variants.product_id`)

このサンプルデータでSQLFiddleを作成しました: http://sqlfiddle.com/#!2/2264d/1

ユーザーは任意のバリエーション名(product_variants.variant)を入力でき、それに任意の値(product_variants.value)を割り当てることができます。 ユーザーが入力できるバリエーション/値の量に制限はありません。

これが私の問題が発生する場所です:以前に存在しなかったバリアントを持つ製品を誰かが追加するたびに新しいテーブル/列を追加せずに各バリエーションの価格/ SKUを保存します。

各バリエーションの価格は同じかもしれませんが、SKUは各製品に固有です。たとえば、Product 1には6つの異なる組み合わせ(3色* 2素材)があり、Product 2には3つの異なる組み合わせ(3サイズ* 1)しかありません。

私は組み合わせをテキストとして保存することを考えました、すなわち:

+------------+-----------------+-------+------+
| product_id | combination     | price | SKU  |
+------------+-----------------+-------+------+
| 1          | red-wool        | 50.00 | A121 |
| 1          | red-polyester   | 50.00 | A122 |
| 1          | blue-wool       | 50.00 | A123 |
| 1          | blue-polyester  | 50.00 | A124 |
| 1          | green-wool      | 50.00 | A125 |
| 1          | green-polyester | 50.00 | A125 |
| 2          | small           | 4.00  | CD12 |
| 2          | medium          | 4.00  | CD13 |
| 2          | large           | 3.50  | CD14 |
+------------+-----------------+-------+------+

しかし、このデータを表現するより良い、正規化された方法がなければなりません。架空の状況:10ドル未満の青い製品を検索できるようにしたいと考えています。上記のデータベース構造では、テキストを解析せずに行うことは不可能であり、それは私が避けたいものです。

どんな助け/提案もありがたいです=)

19
Zaki Aziz

問題に正規化を適用すると、解決策は次のようになります。実行してFiddleで確認する

フィドル

CREATE TABLE products 
    (
     product_id int auto_increment primary key, 
     name varchar(20), 
     description varchar(30)

    );

INSERT INTO products
(name, description)
VALUES
('Rug', 'A cool rug'  ),
('Cup', 'A coffee cup');

create table variants (variant_id int auto_increment primary key,
                       variant varchar(50)
                       );
insert into variants (variant)
values ('color'),('material'),('size') ;   
create table variant_value(value_id int auto_increment primary key, 
                           variant_id int ,
                           value varchar(50)
                           );

insert into variant_value (variant_id,value)
values (1 ,'red'),(1 ,'blue'),(1 ,'green'),
        (2 ,'wool'),(2 ,'polyester'),
        (3 ,'small'),(3 ,'medium'),(3 ,'large');



create table product_Variants( product_Variants_id int  auto_increment primary key,
                            product_id int,
                            productVariantName varchar(50),
                            sku varchar(50),
                            price float
                            );




create table product_details(product_detail_id int auto_increment primary key,
                             product_Variants_id int,

                             value_id int
                             );

insert into product_Variants(product_id,productVariantName,sku,price)
values (1,'red-wool' ,'a121',50);

insert into product_details(product_Variants_id , value_id)
values( 1,1),(1,4);

insert into product_Variants(product_id,productVariantName,sku,price)
values (1,'red-polyester' ,'a122',50);

insert into product_details(product_Variants_id , value_id)
values( 2,1),(2,5);
33
sahalMoidu

問題の一部は、製品とSKUの間の混乱から生じます。

「XYZプルオーバーMサイズブルーモデル」を販売する場合、後者はSKUに対応します。 XYZプルオーバー(製品)として販売されており、属性(サイズと色)のセットを持ち、それぞれに潜在的な値のセットがあります。そして、後者のすべての可能な組み合わせが有効な成果物を生み出すとは限らないかもしれません:あなたは不条理に薄くて長いジーンズを見つけることができません。 SKU、製品、属性、属性値。

そして、ユーザーが10ドルの青いプルオーバーを望んでいるとき、彼は実際には製品カテゴリー内のSKUを探しています。

上記があなたの混乱を解消し、あなたの問題と質問がどこから来たかを望んでいます.

スキーマに関しては、次のようなものが必要です。


製品

  • #製品番号
  • 名前
  • 解説

オプションで、以下も追加します。

  • 価格
  • 在庫あり

これはmarketing関連テーブルです。他には何もありません。マーケティング以外でanythingがアプリケーションの製品を使用している場合は、最終的には苦痛の世界になります。

価格が存在する場合、それはSKUでnullのときにフィールドに入力するために使用されるマスター価格です。これにより、価格入力がよりユーザーフレンドリーになります。

in_stockは説明通りのフラグであり、トリガーによって理想的に維持されます。 anyその製品に関連するSKUの在庫がある場合は、trueである必要があります。


製品の属性

  • 製品番号
  • #attribute_id
  • 名前

product_attribute_values

  • attribute_id
  • #value_id

これは、青、赤、S、M、Lなどの値とともに、色、サイズなどを保持します。

Product_idフィールドに注意してください:製品ごとに新しい属性と値のセットを作成します。商品によりサイズが異なります。 S、M、Lなどの場合もあります。それ以外の場合は、38、40、42などになります。時には、サイズで十分です。それ以外の場合は、幅と長さが必要です。青はこの製品に有効な色かもしれません。別のものは、ネイビー、ロイヤルブルー、ティールなどを提供するかもしれません。ある製品の属性と別の製品の属性との間に何らかの関係があると仮定しないでください。それらが存在する場合、類似点は完全に表面的なものであり、偶然のものです。


SKU

  • 製品番号
  • #sku_id
  • 価格

オプションで、以下を追加します。

  • 名前
  • barcode
  • 株式

これは、出荷される成果物に対応します。

下にある最も重要な表です。 Thisは、product_idではなく、ほぼ確実に顧客の注文で参照されるものです。また、在庫管理などのために参照する必要があります。 (私がこれまでに見た唯一の例外は、後者の2つのポイントで、本当に汎用的なものを販売する場合です。しかし、それでも、私の経験でこれに対処するより良い方法は、交換可能なSKU間のn-m関係を投げることです。)

名前フィールドを追加する場合、これは主に便宜上のものです。 nullのままにした場合は、アプリ側コードを使用して一般的な製品の名前に対応させ、必要に応じて関連する属性名と値で展開します。塗りつぶすことで、後者の一般的な名前(「リーバイス501、W:32、L:32、色:ダークブルー」)をより自然なもの(「リーバイス501、32x32、ダークブルー」)に言い換えることができます。

重要な場合は、バックグラウンドで複式簿記スキーマを使用して、長期的にはトリガーを使用して在庫をより適切に維持します。これにより、実際に発生する多数のシナリオの中で、在庫ありで現在出荷可能(実際にここで必要な数値)と在庫ありですでに販売済みかを区別できます。ああ、...キロやリットルで測定されたものを販売する必要がある場合、整数ではなく数値になることがあります。その場合、顧客が.1ラップトップの注文を送信しないように、必ずis_intフラグを追加してください。


product_variants

  • 製品番号
  • #sku_id
  • #attribute_id
  • value_id

これにより、デフォルト名を生成するために、deliverableのIDが対応する属性と値にリンクされます。

主キーはオンです(sku_id、attribute_id)。

あなたはproduct_idフィールドに異常があるかもしれません。参照する外部キーを追加しない限り、次のようになります。

  • SKU(product_id、sku_id)
  • product_attributes(product_id、attribute_id)
  • product_attribute_values(attribute_id、value_id)

(これらの外部キーを追加する場合は、対応するタプルの追加の一意のインデックスを忘れないでください。)


結論として、3つの補足説明があります。

まず、フローに関して、属性と値のすべての組み合わせが有効な成果物を生成するわけではないことをもう一度強調しておきます。幅は28-42で長さは28-42かもしれませんが、真剣に細い28x42ジーンズを見ることはないでしょう。デフォルトでは、すべての製品のすべての可能なバリエーションを自動的に入力しないでください。必要に応じてそれらを有効/無効にするUIを追加し、名前、バーコード、価格フィールドと一緒にデフォルトでチェックするようにします。 (名前と価格は通常空白のままですが、他のオプションの販売を継続する間、いつか、色が廃止されているという理由で、青いプルオーバーでのみ販売を整理する必要があります。)

次に、製品オプションをさらに管理する必要がある場合、その多くは実際には変装した製品属性であり、在庫管理に関して考慮する必要がある新しいSKUを生成しないものであることを覚えておいてください。たとえば、ラップトップのより大きなHDオプションは、同じ製品(通常のHDサイズと大きなHDサイズ)のバリエーションであり、UIの考慮事項(非常に有効)のためにオプションとして偽装されています。対照的に、ラップトップをクリスマスギフトとしてラッピングすることは、簿記用語で完全に別個のSKU(例:.8mのギフトラップ)を参照する本物のオプションです。スタッフの時間の。

最後に、属性、その値、および後続のバリアントの順序付け方法を考え出す必要があります。このため、最も簡単なのは、属性と値のテーブルの追加の位置フィールドを投げることです。

16

4つのテーブルを使用します。

generic_product: product_id, name, description 

例えば1、「ラグ」、「コーヒーラグ」/ 2、「マグ」、「コーヒーマグ」

generic_product_property: product_id, property_id, property_name 

例えば1、10、 'カラー'/1、11、 'マテリアル'

sellable_product: sku, product_id, price 

例えば「A121」、1、50.00 /「A122」、1、45.00

sellable_product_property: sku, property_id, property_value 

例えば'A121'、10、 '赤'/'A121'、11、 'ウール'/'A122'、10、 '緑'/'A122'、11、 'ウール'

これにより、ユーザーは希望する販売可能な製品のプロパティを定義できます。

アプリケーションは、ビジネスロジックを使用して、sellable_productsが完全に記述されていることを確認する必要があります(該当するすべての一般的な製品プロパティについて、販売可能な製品プロパティが定義されていることを確認してください)。

5
xwoker

これは、SOで彼女がしばらく前に見た別の質問に似ています

データベースの設計:どちらがより良いアプローチですか?

そこを見ると、基本的に同じ狭い(属性ベースの)対広いテーブルの質問をしていることがわかります。シナリオに応じて両方を使用しましたが、現時点での実装方法には十分注意します。そして、それらのバリアントをSKUに一致させるための適切な方法が実際にはない(少なくとも私が考えることはできない)という事実は、テーブルを変更することを強いる可能性があります。

非常に多くの異なるバリアントがある場合は、Key-Valueデータベースまたは他のいくつかのNoSQLソリューションを調べることもできます。

1
Brad

一般的には、いわゆるハタやジャンクディメンションを探しています。基本的にそれはすべての組み合わせの単なる行です。@ sahalMoiduのスキーマは、あなたが求めているものを提供するように見えます。

しかし、正規化に夢中になる前に、データベースがデータを格納する(トランザクションなど)か、データを取得する(ディメンション、レポートなど)かを知る必要があります。トランザクションデータベースであっても、正規化によって何を達成しようとしているのかを自問する必要があります。

1
Andrew

SKUが主キーです。 SKUを使用して、バリアントテーブルへの外部キーの関係を設定できます。 productidを完全に忘れてください。

テーブルを作成x(sku、価格、説明)主キーsk

0
danny117