0

av次のような属性値テーブルがあります。

| attribute | value |
~~~~~~~~~~~~~~~~~~~~~
| a1        | A1    |
| b1        | BB1   |
| b2        | BB2   |

簡単にするために、と列のvarchar(255)両方attributevalue、の一意のインデックスを想定しますattribute

クエリで特定の属性の値を使用する必要があります。これは次のようになります。

SELECT *
FROM   t1
      ,t2
WHERE  t1.a1 = "A1"  -- Value of "a1" attribute
 AND   t1.id = t2.id
 AND   t2.b1 = "BB1"  -- Value of "b1" attribute
 AND   t2.b2 = "BB2"  -- Value of "b2" attribute

テーブルと属性の数を増やすと拡張性の高いSybaseASE(12または15)でこれを行うエレガントな方法はありますか?

「スケール」とは、4〜5個の結合されたテーブル全体で必要な最大10〜20個の属性を意味します

私は次の解決策を考えることができますが、それらはすべてひどいようです:


解決策1:明らか:属性ごとに1回、AVテーブルに参加する

SELECT *
FROM   t1
      ,t2
      ,av AS 'av_a1'
      ,av AS 'av_b1'
      ,av AS 'av_b2'
WHERE  t1.a1 = av_a1.value
 AND   t1.id = t2.id
 AND   t2.b1 = av_b1.value
 AND   t2.b2 = av_b2.value
 AND   av_a1.attribute = "a1"
 AND   av_b1.attribute = "b1"
 AND   av_b2.attribute = "b2"

長所:明らかです。

短所:コード品質、そしておそらくパフォーマンスに関しては、スケーリングが非常に不十分です。


解決策2:変数を使用した複数の結合の問題を回避する

declare @a1 varchar(255)
select  @a1 = value FROM av WHERE attribute = "a1"
declare @b1 varchar(255)
select  @b1 = value FROM av WHERE attribute = "b1"
declare @b2 varchar(255)
select  @b2 = value FROM av WHERE attribute = "b2"

SELECT *
FROM   t1
      ,t2
WHERE  t1.a1 = @a1
 AND   t1.id = t2.id
 AND   t2.b1 = @b1
 AND   t2.b2 = @b2

長所:余分な結合がなくなるため、クエリのパフォーマンスが低下します。

短所:コードの品質に関しては、スケーリングがやや不十分です(新しい属性を持つ新しい変数を追加する必要があります)。


より良い解決策はありますか?

4

2 に答える 2

1

ステートメントの追加の句が何のためにあるのかわかりませんwhere(一方のテーブルの値を他方のテーブルの属性と比較するため)。以下は、結合前に属性を平坦化します。

SELECT *
FROM   t1 join
       t2
       on t1.id = t2.id join
       (select av.id,
               MAX(case when av.attribute = 'a1' then av.value end) as a1,
               MAX(case when av.attribute = 'b1' then av.value end) as b1,
               MAX(case when av.attribute = 'b2' then av.value end) as b2
        from av
        group by av.id
       ) attr
       on attr.id = t1.id

これは、属性に重複がないことを前提として機能します。通常、属性テーブルを使用する場合は重複しません。必要に応じて条件を追加できますがwhere、なぜそこにあるのか理解できませんでした。

また、ANSI 標準の結合構文に切り替える必要があります。

ID がない場合は、基本的に同じことができます。

SELECT *
FROM   t1 join
       t2
       on t1.id = t2.id cross join
       (select MAX(case when av.attribute = 'a1' then av.value end) as a1,
               MAX(case when av.attribute = 'b1' then av.value end) as b1,
               MAX(case when av.attribute = 'b2' then av.value end) as b2
        from av
       ) attr
       on attr.id = t1.id
where <whatever you want>
于 2013-01-22T21:34:49.157 に答える
0

Entity-Attribute-Value 設計の使用は基本的に非リレーショナルであるため、行が 1 つの論理エンティティの属性を記述しているかのように SQL でクエリを実行するのは厄介で非効率的です。

SQL でこれを行うコストを軽減するために、データベースに保存されているすべての行をフェッチし、一度に 1 行ずつ、アプリケーション コードのエンティティ インスタンスに属性を適用することをよくお勧めします。

これは、私が何を意味するかを示すPHPコードの例を含む別のSOの質問です:
1つのクエリで要約結果を作成する


あなたのコメントと反対票を再投稿してください:

あなたはここでメッセンジャーを撃っています。

あなたは尋ねました:

テーブルと属性の数を増やすと、Sybase ASE (12 または 15) でこれを行うエレガントな方法はありますか?

複数行の EAV データを 1 行の結果セットにクエリする方法は、結合またはピボットのいずれであっても、属性のセットを知っている必要があり、これらはクエリの準備時に修正されます。SQL はリレーショナル モデルに基づいているため、クエリの実行時に結果セットの列を動的に拡張することはできません。

したがって、テーブルと属性の数が時々拡大するデータ モデルがある場合、属性を追加するたびにピボット クエリ コードを変更する必要があります。

個別の属性の数に基づいて動的にピボット クエリを生成できますが、現在の属性をクエリしてからクエリを作成する必要があるため、アプリケーション コードも必要です。

別の方法として、結果セットの行ごとに 1 つの属性ですべてのデータをフェッチし、アプリケーション側でそれらを論理エンティティに "再構築" するコードを記述します。

動的なピボット クエリには、クエリの前後に常にアプリケーション コードが必要です。

その答えが気に入らなくてすみません。

于 2013-01-22T22:43:19.577 に答える