扁平化一对多关系

时间:2013-07-09 23:27:03

标签: sql sql-server tsql

我当前的架构如下所示:

PersonType (PersonTypeID, Name, Description)

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

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

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

也就是说,一个人属于某种类型。例如,客户。对于每个PersonType,可以动态添加其他字段来存储有关PersonType的内容。对于Customer,我们可能希望向PersonDynamicField添加字段,例如LikesChocolate,FavoriteColor,HappinessScale等。这些字段的值将存储在PersonDynamicFieldValue中。

我希望我的写作有道理。

我想做的是一个可以展平此结构并返回如下结果的查询:

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

我有点被困,甚至不知道从哪里开始。

你能帮忙吗?

2 个答案:

答案 0 :(得分: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 |

答案 1 :(得分:-2)

您想要的通常称为数据透视,SQL Server的操作可能有所帮助。请查看MSDN上的这篇文章,例如:http://msdn.microsoft.com/en-us/library/ms177410(v=sql.105).aspx