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

在 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

优点:不再有额外的连接使查询变得丑陋且性能不佳。

缺点:就代码质量而言,扩展性有些差(需要添加具有新属性的新变量)。


有更好的解决方案吗?

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 设计本质上是非关系型的,因此在 SQL 中查询它必然是笨拙和低效的,就好像行描述了一个逻辑实体的属性一样。

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

这是另一个 SO 问题,示例 PHP 代码演示了我的意思:
使用一个查询创建摘要结果


重新发表您的评论并投反对票:

你在这里射信使。

您询问:

在 Sybase ASE(12 或 15)中是否有一种优雅的方法可以随着我们增加表和属性的数量而很好地扩展?

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

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

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

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

动态数据透视查询总是需要应用程序代码——在查询之前或之后。

很抱歉你不喜欢这个答案。

于 2013-01-22T22:43:19.577 回答