2013-07-09 34 views
1

我目前的架构是这样的:压扁1对多的关系

PersonType (PersonTypeID, Name, Description) 

Person (PersonID,PersonTypeID, FirstName, ...) 

PersonDynamicField (PersonDynamicFieldID, PersonTypeID, Name, Description, DataType, DefaultValue, ...) 

PersonDynamicFieldValue (PersonDynamicFieldValueID, PersonDynamicFieldID, PersonID, Value, ...) 

也就是说,一个人是某一类型的。例如,客户。对于每个PersonType,可以动态地添加附加字段来存储有关PersonType的信息。对于客户,我们可能需要向PersonDynamicField添加字段,例如LikesChocolate,FavoriteColor,HappinessScale等。这些字段的值将存储在PersonDynamicFieldValue中。

我希望我的写作很有意义。

我想什么做的,是可以拉平这种结构,并返回寻找这样的结果的查询:

PersonID, PersonTypeID, FirstName, LikesChocolate, FavoriteColor, HappinessScale 
1, 2, Robert, 1, Green, 9 
2, 2, John, 0, Orange, 5 
... 

我有点卡住,真的不知道从哪里开始,甚至。

你能帮忙吗?

回答

4

为了得到你想要的结果,有几种方法可以将数据行转换为列。

从SQL Server 2005开始,您可以使用PIVOT函数。代码的基本结构将为:

SELECT personid, persontypeid, firstname,[FavoriteColor],[HappinessScale],[LikesChocolate] 
from 
( 
    select p.personid, p.persontypeid, p.firstname, f.name fields, v.value 
    from person p 
    inner join persontype pt 
    on p.persontypeid = pt.persontypeid 
    left join PersonDynamicField f 
    on p.PersonTypeID = f.PersonTypeID 
    left join PersonDynamicFieldValue v 
    on f.PersonDynamicFieldID = v.PersonDynamicFieldID 
    and p.personid = v.personid 
) x 
pivot 
( 
    max(value) 
    for fields in ([FavoriteColor],[HappinessScale],[LikesChocolate]) 
) p; 

请参阅SQL Fiddle with Demo。使用PIVOT将会遇到的一个问题是,它要求将值转换为列的值在运行时是已知的。对于你的情况,这似乎是不可能的,因为值可能会改变。其结果是,你将不得不使用动态SQL得到的结果:

DECLARE @cols AS NVARCHAR(MAX), 
    @query AS NVARCHAR(MAX) 

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(Name) 
        from PersonDynamicField 
        where PersonTypeID = 2 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

set @query = 'SELECT personid, persontypeid, firstname,' + @cols + ' 
      from 
      (
       select p.personid, 
       p.persontypeid, 
       p.firstname, 
       f.name fields, 
       v.value 
       from person p 
       inner join persontype pt 
       on p.persontypeid = pt.persontypeid 
       left join PersonDynamicField f 
       on p.PersonTypeID = f.PersonTypeID 
       left join PersonDynamicFieldValue v 
       on f.PersonDynamicFieldID = v.PersonDynamicFieldID 
       and p.personid = v.personid 
      ) x 
      pivot 
      (
       max(value) 
       for fields in (' + @cols + ') 
      ) p ' 


execute(@query); 

SQL Fiddle with Demo。这些会给出结果:

| PERSONID | PERSONTYPEID | FIRSTNAME | FAVORITECOLOR | HAPPINESSSCALE | LIKESCHOCOLATE | 
----------------------------------------------------------------------------------------- 
|  1 |   2 | Robert |   Green |    9 |    1 | 
|  2 |   2 |  John |  Orange |    5 |    0 | 
+0

非常感谢@bluefeet。这是我寻找的功能,并做我需要的。只是一件事......你能简单地解释一下以“Select @cols ...”开头的声明吗?我知道它做了什么,但不太明白。谢谢。 – PostureOfLearning

+0

@Rob这是为每个人类型id生成不同字段名称的列表。当使用PIVOT时,必须在运行时知道列,以便代码行创建列名称的列表。 – Taryn