4

ケース:

テーブル:

product:
product_id|name        |
------------------------
1         |iphone 4    |
2         |gallaxy 2   |
3         |blackbery 6 |

product_attribute:

id|product_id|attribute_id
--------------------------------------------------
 1 |1        |2
 2 |1        |6
 .    .        .

attribute:
------------------------------
attribute_id|name  |value|
        1   |width |300
        2   |width |320
        3   |width |310
        4   |height|390
        5   |height|370
        6   |height|380

結果が得られるはずです:

product_id|height|width
 1        |380   |320
 ......................

編集: 高さと幅の属性は、製品属性の唯一の部分です。製品は、eav db デザインを選択するため、magento で行ったように、ユーザーがバックエンドで動的に追加できる必要があります。製品の名前がわからない場合は、可能であればクエリを書いてください。

ありがとう

4

3 に答える 3

6

これを実装するにはいくつかの方法があります。このようなものは、属性値ごとにテーブルに複数回結合して機能するはずです。

SELECT p.product_id,
    a.value height,
    a2.value width
FROM Product p
    JOIN Product_Attribute pa ON p.product_id = pa.product_id 
    JOIN Attribute a ON pa.attribute_id = a.attribute_id AND a.name = 'height'
    JOIN Product_Attribute pa2 ON p.product_id = pa2.product_id 
    JOIN Attribute a2 ON pa2.attribute_id = a2.attribute_id AND a2.name = 'width'

そして、ここにFiddleがあります。

MAX と GROUP BY を使用した、私が個人的に好む別のアプローチを次に示します。

SELECT p.product_id,
    MAX(Case WHEN a.name = 'height' THEN a.value END) height,
    MAX(Case WHEN a.name = 'width' THEN a.value END) width
FROM Product p
    JOIN Product_Attribute pa ON p.product_id = pa.product_id 
    JOIN Attribute a ON pa.attribute_id = a.attribute_id 
GROUP BY p.product_id

幸運を。

于 2013-02-06T23:27:27.890 に答える
3

1 つのアプローチは、SELECT リストで相関サブクエリを使用することですが、これは大規模なセットでのパフォーマンスには最適ではない可能性があります。product テーブルから数行だけ取得する場合は、悪くありません。(必ず適切なインデックスが必要になります。)

SELECT p.product_id
     , ( SELECT a1.value
           FROM attribute a1
           JOIN product_attribute q1
             ON q1.attribute_id = a1.attribute_id
          WHERE q1.product_id = p.product_id
            AND a1.attribute_name = 'height'
          ORDER BY a1.id
          LIMIT 0,1
       ) AS height_1
     , ( SELECT a2.value
           FROM attribute a2
           JOIN product_attribute q2
             ON q2.attribute_id = a2.attribute_id
          WHERE q2.product_id = p.product_id
            AND a2.attribute_name = 'width'
          ORDER BY a2.id
          LIMIT 0,1
       ) AS width_1
  FROM product p
 WHERE p.product_id = 1

このクエリは、product からの行を、属性の値 (存在する場合) と共に返します。属性値が見つからない場合、クエリは属性値の代わりに NULL を返します。(これは、相関サブクエリの代わりに INNER JOIN を使用するクエリの動作とは異なります...属性または product_attribute テーブルから「欠落している」行が、返される製品から行を除外します。)

LIMIT 句の目的は、サブクエリが複数の行を返さないことを保証することです。(SELECT リストのサブクエリが複数の行を返す場合、MySQL はエラーを返します。) ORDER BY の目的は、サブクエリを満たす行が複数ある場合にクエリを決定論的にすることです。 . (ORDER BY 句がない場合、複数の行がある場合、MySQL は選択した行を任意に返すことができます。)

「多値」属性の場合、同じアプローチが機能します。サブクエリを追加するだけですが、2 番目の属性値を返すには LIMIT 1,1 を指定し、3 番目の値を返すには LIMIT 2,1 を指定します。


(ああ、リレーショナル データベースに実装された EAV モデルの喜びです。)


ファローアップ:

Q:「... eav db で発生するより一般的なケースで、以前はどの属性名を持っているかわかりませんでした。」

A:リレーショナル モデルは、タプルに特定の型の特定の数の列が含まれるという原則に基づいています。

あなたが(明らかに)やろうとしているのは、クエリを実行したときに可変数の列を返すことです。SELECT ステートメントには、返される式の特定のリストが含まれます。これは変更できず、各式によって返される値のデータ型は行ごとに異なりません。

上記のクエリは、商品ごとに「height」属性値の 1 つのインスタンスと「width」属性値の 1 つのインスタンスを返します。

より「より一般的なケース」では、各属性値が個別の行に返されることが実際に期待されます。

製品に関連付けられている属性が「事前に」わからない場合の、より一般的なクエリは次のようになります。

SELECT p.product_id
     , a.attribute_id
     , a.name         AS attribute_name
     , a.value        AS attribute_value
  FROM product p
  LEFT
  JOIN product_attribute q
    ON q.product_id = p.product_id
  LEFT
  JOIN attribute a
    ON a.attribute_id = q.attribute_id
 WHERE p.product_id = 1
 ORDER
    BY p.product_id
     , a.name
     , a.attribute_id

これにより、簡単に処理できる結果セットが返されます。

product_id attribute_id attribute_name attribute_value
---------- ------------ -------------- ---------------
         1            6 height         380
         1            2 width          320

Q:「2 段階で行う必要があるように見えます: 1. 製品のすべての属性名を取得します。2. 次に、for ループで属性名のサーバー側コードを含むコードを取得します」

A:いいえ、1 つのクエリで製品のすべての属性名と値のペアが返されるようです。各属性の名前/値は別の行になります。

データベースに対して追加のクエリを生成するために「for ループ」を使用する必要はありません。はい、それは可能ですが、まったく不要です。

データベースに対して実行する別のクエリを作成して、指定した形式で結果セットを返すという奇妙な要件がある場合は、「より一般的なケース」ステートメントから結果セットを処理するために行う処理が何であれ、おそらくより効率的です。データベースに対してこれ以上クエリを実行せずに、結果セットを処理するだけです。

次のような結果セットを返す必要がある場合:

 product_id height width
 ---------- ------ -----
          1 380    320

(別のクエリを作成するという奇妙な要件です)「より一般的なクエリ」からの結果セットを使用して、次のようなクエリを生成することは完全に可能です。

SELECT 1 AS product_id, '380' AS height, '320' AS width

このような演習はかなり無意味ですが、以前に返されなかった新しい情報が返されていないことを考えると、処理する必要がある別の結果セットがあり、不要なオーバーヘッドが大量に発生しているように思えます。

于 2013-02-06T23:29:51.977 に答える
1

最初に言っておきますが、これは本当にお粗末なデザインです。 現在のアプローチでは、必要な結果を得るために、複数のサブクエリまたはテーブル エイリアスを使用した結合を実行する必要があります。

SELECT 
    product_id,
    (
        SELECT product_attribute.value 
        FROM product_attribute, attribute 
        WHERE product_attribute.product_id=product.product_id 
        AND product_attribute.attribute_id=attribute.attribute_id
        AND product_attribute.name = 'width'
    ) AS 'width',
    (
        SELECT product_attribute.value 
        FROM product_attribute, attribute 
        WHERE product_attribute.product_id=product.product_id 
        AND product_attribute.attribute_id=attribute.attribute_id
        AND product_attribute.name = 'height'
    ) AS 'height'
FROM
    product
ORDER BY 
    ...      

提案させてください:

attribute
   attribute_sid  (eg, string id)

product
   product_id
   name
   ...

product_attribute
   product_id   (foreign key to product table)
   attribute_sid  (foreign key to attribute table)
   value   

このようにして、属性の決定的なリストと、製品ごとに 1 つの属性値が得られます。

SELECT attribute_sid, value FROM product_attribute WHERE product_id = 1

dict... は、 、array、またはに便利に配置できるすべての属性と値を取得しますmap

于 2013-02-06T23:30:54.183 に答える