2

私のシステムには次の(たとえば簡略化された)テーブルがあります。

ER図を表示する

その目的は、機能を特定のカテゴリに指定してから、サブカテゴリまたは製品レベルでオーバーライドできるようにすることです。

さまざまな属性を持つさまざまなタイプの機能があり、それらのタイプは、機能と1:1の関係を持つ「拡張」テーブルによって表されます。

たとえば、次のようにしましょう。

  • すべてのコンピューターとライトにはACアダプターがあります(カテゴリー)
  • すべてのコンピューターにCPUが搭載されています(カテゴリー)
  • すべてのラップトップとタブレットにはバッテリーがあります(サブカテゴリ)
  • すべてのMacBookProにはHDMIポートがあります(製品)
  • すべてのMacBookProおよびiPadにはRetinaディスプレイが搭載されています(製品)

これは次のようにモデル化されます。

カテゴリ:

  • feature_container:id:1
  • カテゴリ:id:1、名前:"コンピュータ"
  • feature_container:id:2
  • カテゴリ:id:2、名前:"ライト"

サブカテゴリ:

  • feature_container:id:3
  • サブカテゴリ:id:3、category_id:1、名前:"デスクトップ"
  • feature_container:id:4
  • サブカテゴリ:id:4、category_id:1、名前:"ラップトップ"
  • feature_container:id:5
  • サブカテゴリ:id:5、category_id:1、name: "Tablet"

  • feature_container:id:6

  • サブカテゴリ:id:6 category_id:2、名前: "Floor Light"
  • feature_container:id:7
  • サブカテゴリ:id:7、category_id:2、名前:"電気スタンド"

製品:

  • feature_container:id:7
  • 製品:id:7、subcategory_id:4、名前: "Apple MacBookAir"
  • feature_container:id:8
  • 製品:id:8、subcategory_id:4、名前: "Apple MacBook Pro"
  • feature_container:id:9
  • 製品:id:9、subcategory_id:5、名前: "Apple iPad"

カテゴリに適用される機能:

  • 機能:id:1、feature_container_id:1
  • has_ac_adapter_feature:id:1、model_number: "ABC"

  • 機能:id:2、feature_container_id:2

  • has_ac_adapter_feature:id:2、model_number: "DEF"

  • 機能:id:3、feature_container_id:1

  • has_cpu_feature:id:3、model_number: "123"

サブカテゴリに適用される機能:

  • 機能:id:4、feature_container_id:4
  • has_battery_feature:id:4、battery_type:"リチウムイオン"
  • 機能:id:5、feature_container_id:5
  • has_battery_feature:id:5、battery_type:"リチウムイオン"

製品に適用される機能:

  • 機能:id:6、feature_container_id:8
  • has_retina_display_feature:id:6
  • 機能:id:7、feature_container_id:9
  • has_retina_display_feature:id:7
  • 機能:id:8、feature_container_id:8
  • has_hdmi_port_feature:id:8

Light階層のデータをわざわざ挿入することはしませんが、あなたはその考えを理解します。私が持っていることを覚えておいてください:

  • 何百万もの製品
  • 何千ものサブカテゴリ
  • 何百ものカテゴリ
  • 主にサブカテゴリで定義されている数千の機能ですが、製品やカテゴリで定義されているものもあります。
  • 通常はカテゴリレベル(ACアダプタ)で定義される機能が、実際には製品レベルでのみ定義される可能性があることは言うまでもありません。これはビジネス上の呼びかけであり、柔軟性と保守性によって推進されます。つまり、どの機能もどのレベルでも割り当てることができると想定する必要があります。

次のことを問い合わせたい:

CPUとACアダプターを備え、(RetinaディスプレイまたはHDMIポート)を備えたすべての製品を教えてください

私は得る必要があります:

  • Apple MacBook Pro
  • Apple iPad

これが私が試したことです...

私はこのようなものから始めました:

http://sqlfiddle.com/#!4/2f6cd/4/0

これは継承の問題に対処しようとしますが、これでフィルタリングを開始すると(製品にこの機能とその機能がある場合)、どの製品に複数の機能や機能があるかを簡単に見つけることができないことにすぐに気付きました(または?)。

それから私はこのようなことを始めました:

SELECT prd.id AS prd_id,
   CASE
       WHEN    prd_lvl.ac_ftr = 1
            OR cat_lvl.ac_ftr = 1
            OR scat_lvl.ac_ftr = 1
       THEN
           1
       ELSE
           0
   END
       AS ac_ftr
FROM product prd
   LEFT JOIN (SELECT prd.id AS prd_id,
                     prd.name AS prd_name,
                     NVL2 (ac_ftr.id, 1, 0) AS ac_ftr,
                     NVL2 (cpu_ftr.id, 1, 0) AS cpu_ftr,
                     NVL2 (bat_ftr.id, 1, 0) AS bat_ftr,
                     NVL2 (hdmi_ftr.id, 1, 0) AS hdmi_ftr,
                     NVL2 (ret_ftr.id, 1, 0) AS ret_ftr
                FROM feature_container fc
                     INNER JOIN product prd
                         ON fc.id = prd.id
                     INNER JOIN feature ftr
                         ON fc.id = ftr.feature_container_id
                     LEFT JOIN has_ac_adapter_feature ac_ftr
                         ON ftr.id = ac_ftr.id
                     LEFT JOIN has_cpu_feature cpu_ftr
                         ON ftr.id = cpu_ftr.id
                     LEFT JOIN has_battery_feature bat_ftr
                         ON ftr.id = bat_ftr.id
                     LEFT JOIN has_hdmi_port_feature hdmi_ftr
                         ON ftr.id = hdmi_ftr.id
                     LEFT JOIN has_retina_display_feature ret_ftr
                         ON ftr.id = ret_ftr.id) prd_lvl
       ON prd.id = prd_lvl.prd_id
   LEFT JOIN (      --All Products and subcategory-level-features assigned
              SELECT prd.id AS prd_id,
                     prd.name AS prd_name,
                     NVL2 (ac_ftr.id, 1, 0) AS ac_ftr,
                     NVL2 (cpu_ftr.id, 1, 0) AS cpu_ftr,
                     NVL2 (bat_ftr.id, 1, 0) AS bat_ftr,
                     NVL2 (hdmi_ftr.id, 1, 0) AS hdmi_ftr,
                     NVL2 (ret_ftr.id, 1, 0) AS ret_ftr
                FROM feature_container fc
                     INNER JOIN subcategory scat
                         ON fc.id = scat.id
                     INNER JOIN feature ftr
                         ON fc.id = ftr.feature_container_id
                     INNER JOIN product prd
                         ON scat.id = prd.subcategory_id
                     LEFT JOIN has_ac_adapter_feature ac_ftr
                         ON ftr.id = ac_ftr.id
                     LEFT JOIN has_cpu_feature cpu_ftr
                         ON ftr.id = cpu_ftr.id
                     LEFT JOIN has_battery_feature bat_ftr
                         ON ftr.id = bat_ftr.id
                     LEFT JOIN has_hdmi_port_feature hdmi_ftr
                         ON ftr.id = hdmi_ftr.id
                     LEFT JOIN has_retina_display_feature ret_ftr
                         ON ftr.id = ret_ftr.id) scat_lvl
       ON prd.id = scat_lvl.prd_id
   LEFT JOIN (         --All Products and category-level-features assigned
              SELECT prd.id AS prd_id,
                     prd.name AS prd_name,
                     NVL2 (ac_ftr.id, 1, 0) AS ac_ftr,
                     NVL2 (cpu_ftr.id, 1, 0) AS cpu_ftr,
                     NVL2 (bat_ftr.id, 1, 0) AS bat_ftr,
                     NVL2 (hdmi_ftr.id, 1, 0) AS hdmi_ftr,
                     NVL2 (ret_ftr.id, 1, 0) AS ret_ftr
                FROM feature_container fc
                     INNER JOIN category cat
                         ON fc.id = cat.id
                     INNER JOIN feature ftr
                         ON fc.id = ftr.feature_container_id
                     INNER JOIN subcategory scat
                         ON cat.id = scat.category_id
                     INNER JOIN product prd
                         ON scat.id = prd.subcategory_id
                     LEFT JOIN has_ac_adapter_feature ac_ftr
                         ON ftr.id = ac_ftr.id
                     LEFT JOIN has_cpu_feature cpu_ftr
                         ON ftr.id = cpu_ftr.id
                     LEFT JOIN has_battery_feature bat_ftr
                         ON ftr.id = bat_ftr.id
                     LEFT JOIN has_hdmi_port_feature hdmi_ftr
                         ON ftr.id = hdmi_ftr.id
                     LEFT JOIN has_retina_display_feature ret_ftr
                         ON ftr.id = ret_ftr.id) cat_lvl
       ON prd.id = cat_lvl.prd_id order by prd_id

しかし、それは同じ問題を抱えています:私は同じ行に物を置くことができません。この問題を解決する方法について何かアドバイスはありますか?

ありがとう!

4

1 に答える 1

1

あなたがここで構築したものは、EAV モデルよりも悪いものだと思います。すべての属性と値を 1 つのテーブルに格納する代わりに、1000 ほどのテーブルを属性として作成し、実用的な値はほとんどありません。これはクレイジーに聞こえるかもしれませんが、EAV モデルに変更することをお勧めします。クエリは簡単になりますが、それほどではありません。

データ モデルのもう 1 つの大きな問題はfeatureテーブルです。各「実際の」機能 ( などhas_ac_adapter_feature) とfeature_container. 各「実際の」フィーチャ テーブルを 1 つのfeatureテーブルで結合できます。それぞれに 1 つ必要です。

あなたは数千の機能があると述べています。1 つの SQL にすべての「実際の」機能テーブルを含めると、大きすぎるため、常に動的クエリを作成する必要があることを理解していただければ幸いです。

この SQL は、次の質問にどのように答えるかのデモンストレーションとして含めました。

CPU と AC アダプターを搭載し、(Retina ディスプレイまたは HDMI ポート) を備えたすべての製品を教えてください。

私は現在 Oracle DB の近くにいないので、構文が少しずれている可能性があります。ごめん。

WITH 
    AC_ADAPTER_VIEW AS (
        SELECT feature.feature_container_id, ac_ftr.id
        FROM feature
            LEFT JOIN has_ac_adapter_feature ac_ftr
            ON ac_ftr.id = feature.id
    ),
    CPU_VIEW AS (
        SELECT feature.feature_container_id, cpu_ftr.id
        FROM feature
            LEFT JOIN has_cpu_feature cpu_ftr
            ON cpu_ftr.id = feature.id
    ),
    HDMI_VIEW AS (
        SELECT feature.feature_container_id, hdmi_ftr.id
        FROM feature
            LEFT JOIN has_hdmi_port_feature hdmi_ftr
            ON hdmi_ftr.id = feature.id
    ),
    RETINA_VIEW AS (
        SELECT feature.feature_container_id, ret_ftr.id
        FROM feature
            LEFT JOIN has_retina_display_feature ret_ftr
            ON ret_ftr.id = feature.id
    ),
    FEATURE_CONTAINER_VIEW AS (
        SELECT 
             fc.id as feature_container_id,
             ac_ftr.id AS ac_ftr,
             cpu_ftr.id AS cpu_ftr,
             bat_ftr.id AS bat_ftr,
             hdmi_ftr.id AS hdmi_ftr,
             ret_ftr.id AS ret_ftr
        FROM feature_container
             LEFT JOIN AC_ADAPTER_VIEW ac_ftr
                 ON feature_container.id = ac_ftr.feature_container_id
             LEFT JOIN CPU_VIEW cpu_ftr
                 ON feature_container.id = cpu_ftr.feature_container_id
             LEFT JOIN HDMI_VIEW hdmi_ftr
                 ON feature_container.id = hdmi_ftr.feature_container_id
             LEFT JOIN RETINA_VIEW ret_ftr
                 ON feature_container.id = ret_ftr.feature_container_id
    ),
    PRODUCT_VIEW AS (
        SELECT  product.id, FEATURE_CONTAINER_VIEW.*
        FROM    FEATURE_CONTAINER_VIEW
            INNER JOIN product
            ON product.id = FEATURE_CONTAINER_VIEW.feature_container_id
    ),
    SUBCATEGORY_VIEW AS (
        SELECT  product.id, FEATURE_CONTAINER_VIEW.*
        FROM    FEATURE_CONTAINER_VIEW
            INNER JOIN product
            ON product.subcategory_id = FEATURE_CONTAINER_VIEW.feature_container_id
    ), 
    CATEGORY_VIEW AS (
        SELECT  product.id, FEATURE_CONTAINER_VIEW.*
        FROM    FEATURE_CONTAINER_VIEW
            INNER JOIN subcategory
            ON subcategory.category_id = FEATURE_CONTAINER_VIEW.feature_container_id
            INNER JOIN product
            ON subcategory.id = product.subcategory_id
    )
SELECT
    product.*
FROM    
    product
    INNER JOIN PRODUCT_VIEW
        ON PRODUCT_VIEW.id = product.id
    INNER JOIN SUBCATEGORY_VIEW
        ON SUBCATEGORY_VIEW.id = product.id
    INNER JOIN CATEGORY_VIEW
        ON CATEGORY_VIEW.id = product.id
WHERE 
    --Check for CPU
    COALESCE( PRODUCT_VIEW.cpu_ftr, SUBCATEGORY_VIEW.cpu_ftr, CATEGORY_VIEW.cpu_ftr) is not null
    --Check for AC
    AND COALESCE( PRODUCT_VIEW.ac_ftr, SUBCATEGORY_VIEW.ac_ftr, CATEGORY_VIEW.ac_ftr) is not null
    --OR condition
    AND (
        --Check for HDMI
        COALESCE( PRODUCT_VIEW.hdmi_ftr, SUBCATEGORY_VIEW.hdmi_ftr, CATEGORY_VIEW.hdmi_ftr) is not null
        --Check for HDMI
        OR COALESCE( PRODUCT_VIEW.ret_ftr, SUBCATEGORY_VIEW.ret_ftr, CATEGORY_VIEW.ret_ftr) is not null
    )
于 2012-07-18T22:37:27.950 に答える