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