是否有更优雅的方法根据存储在属性值表中的值查询数据?

时间:2013-01-22 20:25:38

标签: sql tsql entity-attribute-value sybase-ase

我有一个属性值表av,如下所示:

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

为简单起见,假设varchar(255)attribute列上的valueattribute上的唯一索引。

我需要在查询中使用特定属性的值,如下所示:

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

是否有一种优雅的方法在Sybase ASE(12或15)中执行此操作,可以很好地扩展,因为我们增加了表和属性的数量?

按“比例”,我的意思是4-5个连接表需要~10-20个属性

我可以想到以下解决方案,所有这些似乎都很糟糕:


解决方案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

优点:没有更多的额外加入,使查询既丑陋又效果不佳。

缺点:就代码质量而言,缩放程度稍差(需要使用新属性添加新变量)。


有更好的解决方案吗?

2 个答案:

答案 0 :(得分: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标准连接语法。

如果你没有身份证,你可以做同样的事情:

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>

答案 1 :(得分:0)

使用Entity-Attribute-Value设计从根本上讲是非关系的,因此在SQL中查询它就像在行中描述一个逻辑实体的属性一样笨拙且效率低下。

为了减轻在SQL中执行此操作的成本,我经常建议在存储在数据库中时获取所有行,然后将属性应用于应用程序代码中的实体实例,一次一行。

这是另一个问题,示例PHP代码展示了我的意思:
Create a summary result with one query


重新评论并发表评论:

你在这里拍摄信使。

你问:

  

在Sybase ASE(12或15)中是否有一种优雅的方法可以在我们增加表和属性的数量时进行扩展?

每个查询多行EAV数据到一行结果集的方法,无论是通过连接还是通过旋转,都需要您知道属性集,并且这些属性在您准备查询时是固定的。由于SQL基于关系模型,因此在查询执行时,结果集的列不能动态扩展。

因此,如果您有一个数据模型,其中表和属性的数量会不时扩展,那么每次添加属性时,您都会发现自己正在更改数据透视查询代码。

您可以根据不同属性的数量动态生成数据透视查询,但这也需要应用程序代码,因为您需要查询当前属性然后构建查询。

另一种方法是获取所有数据,每行结果集一个属性,并编写代码以将它们“重新组合”为应用程序端的逻辑实体。

动态数据透视查询始终需要应用程序代码 - 在查询之前或之后。

对不起,你不喜欢那个答案。