如何将垂直表转换为水平表?

时间:2010-04-15 09:26:02

标签: sql sql-server linq-to-sql parent-child

我有一张桌子人物:

Id Name
1  Person1
2  Person2
3  Person3

我有它的子表简介:

Id PersonId FieldName  Value
1  1        Firstname  Alex
2  1        Lastname   Balmer
3  1        Email      some_email@test.com
4  1        Phone      +1 2 30004000

我想从这两个表中获取数据,如下所示:

Id Name     Firstname Lastname  Email                Phone 
1  Person1  Alex      Balmer    some_email@test.com  +1 2 30004000
  1. 在这样的一行中获取这些垂直(键值,值)值的最优化查询是什么?现在我有一个问题,我做了四个子表到父表的连接,因为我需要得到这四个字段。有些优化肯定是可能的。
  2. 我希望能够在添加新字段(键,值)时以简单的方式修改此查询。做这个的最好方式是什么?要创建一些存储过程吗?
  3. 我想在我的数据库层(C#)中使用强类型并使用LINQ(编程时),这意味着当我在Profile表中添加一些新的Key,Value对时,我想在DB和C#中进行最小的修改如果可能的话。实际上,我正试图在这种情况下获得一些最佳实践。

2 个答案:

答案 0 :(得分:1)

Select 
    P.ID
    , P.Name
    , Case When C.FieldName = 'FirstName' Then C.Value Else NULL END AS FirstName
    , Case When C.FieldName = 'LastName' Then C.Value Else NULL END AS LastName
    , Case When C.FieldName = 'Email' Then C.Value Else NULL END AS Email
    , Case When C.FieldName = 'Phone' Then C.Value Else NULL END AS Phone  
From Person AS P
Inner JOIN Child AS C
ON P.ID = C.PersonID

你可以使用PIVOT;不确定哪一个最容易添加新列。

答案 1 :(得分:1)

使用强类型字段的最佳优化方法是这样做:

CREATE TABLE Persons
(PersonID     int identity(1,1) primary key
,Firstname    varchar(...)
,Lastname     varchar(...)
,Email        varchar(...)
,Phone        varchar(...)
,....
)

然后最优化的查询将是:

SELECT
    PersonID,Firstname,Lastname,Email,Phone
    FROM Persons
    WHERE ...

将所有主列添加到人员表中。如果您需要专门创建其他表:

--one person can play many instruments with this table
CREATE TABLE PersonMusicians
(PersonID               int           --pk   fk to Persons.PersonID     
,InstrumentCode         char(1)       --pk
,...
)

--only one row per person with this table
CREATE TABLE PersonTeachers
(PersonID               int            --pk   fk to Persons.PersonID    
,FavoriteSubjectCode    char(1)
,SchoolName             varchar(...)
)

如果你必须有无限的动态属性字段,那么我会尽可能完全地创建上面的结构(尽可能多的常见字段)然后有一个“AdditionalInfo”表,你可以存储所有的信息,如:

AdditionalInfoFields
FieldID    int identity(1,1) primary key
FieldName  varchar(...)

AdditionalInfo
AdditionalInfoID   int identity(1,1) primary key
PersonID           int   fk to Persons.PersonID  
FieldID            int   fk to AdditionalInfoFields.FieldID    
FieldValue         varchar(..) or you can look into sql_variant

AdditionalInfo.PersonID+FieldID上有一个索引,如果你要搜索所有拥有属性X的人,那么还有另一个像AdditionalInfo.FieldID+PersonID

如果没有上述任何一项,您将需要使用您在选项#1中提到的四个左外连接:

SELECT
    P.ID, p.Name
        , p1.Value AS Firstname
        , p2.value AS Lastname     
        , p3.Value AS Email
        , p4.Value AS Phone
    FROM Persons                 p
        LEFT OUTER JOIN Profile p1 ON p.PersonID=p1.PersonID AND p1.FieldName='Firstname'
        LEFT OUTER JOIN Profile p1 ON p.PersonID=p1.PersonID AND p1.FieldName='Lastname'
        LEFT OUTER JOIN Profile p1 ON p.PersonID=p1.PersonID AND p1.FieldName='Email'
        LEFT OUTER JOIN Profile p1 ON p.PersonID=p1.PersonID AND p1.FieldName='Phone'
    WHERE ....

你总是可以使用这个左连接查询中的索引创建一个物化视图,并为你预先计算数据,这样可以加快它的速度。

相关问题