SQL SELECT和EAV表

时间:2017-02-27 10:57:42

标签: sql database attributes sql-server-express entity-attribute-value

根据我以前的问题,我有以下表格:

  IrisColor 
  ID Description
   1 Blue 
   2 Gray 
   3 Green 
   4 Brown

 SkinColor 
  ID Description
   1 White 
   2 Asian 
   3 Dark       

Gender
  ID Description
   1 Male 
   2 Female 

和属性表

Attributes
  ID Description
   1 SkinColor 
   2 IrisColor 
   3 Gender

还有EAV表:

PersonDetails
  PersonID AttributeID ValueID
   121       1            1
   121       2            2
   121       3            1
   122       1            2
   122       2            1
   122       3            1

因此,如果我想选择名称,属性名称和仅适用于SkinColor的值,我会这样做:

SELECT p.Name,
       a.Description,
       v.Description
       FROM PersonDetails AS sd 
       INNER JOIN Subjects AS p ON sd.PersonID=p.ID 
       INNER JOIN SubjectAttributes AS a ON sd.AttributeID=a.ID
       INNER JOIN SkinColor AS v ON sd.ValueID= v.ID

但我该怎么办如果我想从数据库中选择所有人的所有信息,不仅是肤色,还有虹膜的颜色和性别?

以前我知道从SkinColor我想选择那个值,但在PersonDetails中我也有IrisColor和Gender的值。

INNER JOIN SkinColor AS v ON sd.ValueID = v.ID 这将不再合适。如何用更具动力的东西取而代之?

更新

我用过这句话:

SELECT
    SubjectID,
    SkinColor,
    IrisColor,
    EyeLidFlisure,
    KnownEyeDeffect,
    Ethnicity,
    Height,
    DrivingLicense,
    Gender
FROM
(
SELECT SubjectID, attr.Description as attribute, ValueID from SubjectDetails, SubjectAttributes as attr WHERE SubjectDetails.AttributeID=attr.ID
) as t
PIVOT(MAX(ValueID) FOR attribute IN (SkinColor,IrisColor,Gender,EyeLidFlisure,KnownEyeDeffect,Ethnicity,Height,DrivingLicense)) AS t1

现在,我将所有属性列在单独的列中,但我没有值描述,而是具有值ID。我该怎么办?

3 个答案:

答案 0 :(得分:1)

您的数据模型有点神秘,因为您的人员详细信息中包含了ids。表没有正确的外键关系。您可以将所有属性放在同一个表中。或者为每个属性都有一个单独的表。或者 - 与EAV模型一样 - 将描述直接放入PersonDetails

你需要做这样的事情:

SELECT p.Name,
       sa.Description,
       ic.Description as IrisColor,
       g.Description as gender
FROM PersonDetails sd INNER JOIN
     Subjects p
     ON sd.PersonID = p.ID INNER JOIN
     SubjectAttributes sa
     ON sd.AttributeID = sa.ID 
     ON  LEFT JOIN
     SkinColor sc
     ON sd.ValueID = sc.ID AND sa.Description = 'SkinColor' LEFT JOIN
     IrisColor ic
     ON sd.ValueId = ic.ID AND sa.Description = 'IrisColor' LEFT JOIN
     Gender g
     ON sd.ValueId = g.ID AND sa.Description = 'Gender';

答案 1 :(得分:1)

猜猜你需要从属性字典构建的动态sql

declare @sql varchar(max)=
  'select PersonID , ' +
  +  stuff((select ','+Description + '.Description as ' + Description
             from Attributes
        for xml path ('')),1,1,'')
  + ' from (select PersonID, '
  +  stuff((select ',max(case AttributeID when ' + cast(ID as varchar(5)) +' then ValueID end) as ' + Description
        from Attributes
        for xml path ('')),1,1,'')
  +' from PersonDetails group by PersonID ) pvt' 
  +  (select ' left join ' + Description + ' on pvt.' + Description + ' = '+ Description + '.ID'
        from   Attributes
        for xml path (''));

exec (@sql);

答案 2 :(得分:0)

这将是完整的解决方案(不知道它是否是最简单的......但它有效)

WITH Subject AS (

SELECT
    SubjectID,
    SkinColor,
    IrisColor,
    EyeLidFlisure,
    KnownEyeDeffect,
    Ethnicity,
    Height,
    DrivingLicense,
    Gender
FROM
(
SELECT SubjectID, attr.Description as attribute, ValueID from SubjectDetails, SubjectAttributes as attr WHERE SubjectDetails.AttributeID=attr.ID
) as t
PIVOT(MAX(ValueID) FOR attribute IN (SkinColor,IrisColor,Gender,EyeLidFlisure,KnownEyeDeffect,Ethnicity,Height,DrivingLicense)) AS t1
)

SELECT SubjectID,
whole.Name as Name,
whole.eMail as eMail,
skincolor.Description as SkinColor, 
iriscolor.Description as IrisColor,
eyelid.Description as EyeLidFlisure,
defect.Description as KnownEyeDeffect,
eth.Description as Ethnicity,
height.Description as Height,
dl.Description as DrivingLicense,
gender.Description as Gender

FROM Subject S
Left JOIN Subjects whole ON whole.ID=S.SubjectID
Left JOIN SkinColor skincolor ON S.SkinColor=skincolor.ID
Left JOIN IrisColor iriscolor ON S.IrisColor=iriscolor.ID
Left JOIN EyeLidFlisure eyelid ON S.EyeLidFlisure=eyelid.ID
Left JOIN KnownEyeDeffect defect ON S.KnownEyeDeffect=defect.ID
Left JOIN Ethnicity eth ON S.Ethnicity=eth.ID
Left JOIN Height height ON S.Height=height.ID
Left JOIN DrivingLicense dl ON S.DrivingLicense=dl.ID
Left JOIN Gender gender ON S.Gender=gender.ID