【问题标题】:EAV Select query from spreaded value tablesEAV 从扩展值表中选择查询
【发布时间】:2013-09-08 01:04:33
【问题描述】:

我必须使用以下 SQL Server 数据库结构来查询数据。模型可能是错误的;如果是这样的话,我很感激争论,所以我可以要求改变。如果没有,我需要一个查询来获取我将在下面详述的格式的选项卡式数据。

结构如下:

CLIENTS:

ClientID    ClientName
-----------------------
1           James
2           Leonard
3           Montgomery

ATTRIBUTES:

AttributeID     AttributeName
-----------------------------
1               Rank
2               Date
3               Salary
4               FileRecordsAmount

ATTRIBUTES_STRING:

ClientID    AttributeID     AttributeStringValue
1           1               Captain
2           1               Chief Surgeon
3           1               Chief Engineer

ATTRIBUTES_NUMERIC:

ClientID    AttributeID     AttributeNumericValue
1           4               187
2           4               2
3           4               10

我需要的结果如下:

RESULTS:
----------------------------------------------------------
ClientID    ClientName  Rank            FileRecordsAmount
1           James       Captain         187
2           Leonard     Chief Surgeon   2
3           Montgomery  Chief Engineer  10

我怎样才能做到这一点?

非常感谢!

编辑:这里(对我来说)具有挑战性的问题是属性是动态的......我有 5 个属性表(ATTRIBUTES_STRING、ATTRIBUTES_NUMERIC、ATTRIBUTES_DATE、ATTRIBUTES_BIT、ATTRIBUTES_INT),用户应该能够设置它自己的属性。

【问题讨论】:

  • 好吧;到目前为止,我正在通过代码进行管理;我在 ATTRIBUTES_XXX 表上运行了几个选择并检查是否存在(我有 5 个;字符串、日期、位、双精度和整数的属性表)。我想使用带有直接查询的“更清洁”的解决方案...
  • Read this true story about how EAV tables sank a whole company 然后遵循给出的建议:RUN LIKE HELL! - EAV 是魔鬼 - 要么重新架构,要么离开工作.....
  • 感谢marc的文章,很有意思;但是这种情况并不难(1 个有 240 个字段的表?天哪!);整个布局有 40 个表,“eav”仅“影响”1 个表。好吧,除此之外,您对动态属性有什么建议?谢谢!

标签: sql sql-server entity-attribute-value


【解决方案1】:

您需要一个 SQL 连接。它看起来像这样:

select 
    CLIENTS.ClientID, 
    CLIENTS.ClientName, 
    ATTRIBUTES_STRING1.AttributeStringValue as Rank, 
    ATTRIBUTES_NUMERIC2.AttributeNumericValue as FileRecordsAmount
from 
    CLIENTS,
    ATTRIBUTES ATTRIBUTES1,
    ATTRIBUTES ATTRIBUTES2,
    ATTRIBUTES_STRING ATTRIBUTES_STRING1,
    ATTRIBUTES_NUMERIC ATTRIBUTES_NUMERIC2
where CLIENTS.ClientID = ATTRIBUTES_STRING1.ClientID
and CLIENTS.ClientID = ATTRIBUTES_NUMERIC2.ClientID
and ATTRIBUTES_STRING1.AttributeID = ATTRIBUTES1.AttributeID
and ATTRIBUTES_NUMERIC2.AttributeID = ATTRIBUTES2.AttributeID
and ATTRIBUTES1.AttributeName = 'Rank'
and ATTRIBUTES2.AttributeName = 'FileRecordsAmount'
;

这里是SQL Fiddle 供参考。这是我的第一个 EAV 架构,所以我不会太相信它:)

编辑:下面提供的架构供参考:

create table CLIENTS (
    ClientID integer primary key,
    ClientName varchar(50) not null
);

insert into CLIENTS values (1,'James');
insert into CLIENTS values (2,'Leonard');
insert into CLIENTS values (3,'Montgomery');

create table ATTRIBUTES (
    AttributeID integer primary key,
    AttributeName varchar(50) not null
);

create index ATTRIBUTE_NAME_IDX on ATTRIBUTES (AttributeName);

insert into ATTRIBUTES values (1,'Rank');
insert into ATTRIBUTES values (2,'Date');
insert into ATTRIBUTES values (3,'Salary');
insert into ATTRIBUTES values (4,'FileRecordsAmount');

create table ATTRIBUTES_STRING (
    ClientID integer,
    AttributeID integer not null,
    AttributeStringValue varchar(255) not null,
    primary key (ClientID, AttributeID)
);

insert into ATTRIBUTES_STRING values (1,1,'Captain');
insert into ATTRIBUTES_STRING values (2,1,'Chief Surgeon');
insert into ATTRIBUTES_STRING values (3,1,'Chief Engineer');

create table ATTRIBUTES_NUMERIC (
    ClientID integer,
    AttributeID integer not null,
    AttributeNumericValue numeric(10, 5) not null,
    primary key (ClientID, AttributeID)
);
insert into ATTRIBUTES_NUMERIC values (1,4,187);
insert into ATTRIBUTES_NUMERIC values (2,4,2);
insert into ATTRIBUTES_NUMERIC values (3,4,10);

编辑:修改了选择,使其更容易使用额外的属性进行扩展

【讨论】:

  • 非常感谢你,矮人!我试过小提琴,因为我在某处读过一个引用它的答案,但除了错误“'CONCAT_WS'不是可识别的内置函数名......”之外,我什么也得不到。您提供的解决方案有效,但可能是因为我没有足够澄清(我将编辑我的问题),属性表是动态的。我的意思是,在示例中,我只放了我拥有的五个属性表中的两个。请注意,我已经配置了 4 个属性,但在这种情况下我只使用了其中的 2 个。
  • 对于您希望在结果集中添加的每个附加属性,您必须为ATTRIBUTES 添加一个别名(例如ATTRIBUTES3),另一个对您的ATTRIBUTES_<TYPE> 表的引用(例如ATTRIBUTES_STRING_2), CLIENTClientID 上的ATTRIBUTES_<TYPE> 表之间的连接,ATTRIBUTES_<TYPE>AttributeID 上的ATTRIBUTES 别名之间的连接,以及AttributeName 上的条件(例如AttributeName = 'Salary')。这听起来很复杂,但如果你遵循我在select 语句中建立的模式,你就会掌握它的窍门。
  • 啊,我现在更好地理解了您的问题 - 感谢您的澄清。您有两个选择:或者像我在您的客户端代码中提供的那样构建一个查询,或者像我使用 T-SQL 提供的那样构建一个查询。无论哪种方式,您都需要扫描ATTRIBUTES 表,然后根据可用属性构建查询。如果您可以存储与每个属性关联的类型,您可以像我所做的那样加入正确的ATTRIBUTES_<TYPE> 表,否则您可以加入每个属性的 all 类型(更慢更详细,但它会起作用)。
  • 再次非常感谢您的回答。你给我的提示,加入正确的 ATTRIBUTE_TYPE,将在我的代码中做一些事情来动态地构建“正确”的 sql 语句?
  • 如果可能,在ATTRIBUTES 表中存储一个类型。这将要求您的用户在创建属性时指定类型。
猜你喜欢
  • 1970-01-01
  • 2013-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-28
  • 2015-04-19
相关资源
最近更新 更多