关系表中的多个FK,在一个结果中返回行但在不同列上作为FK连接

时间:2014-01-24 22:03:35

标签: sql sql-server sql-server-2012

我有一个关系表,其中有4个FK回到用户表...“标记”在某个实体上做某些事情的某些用户。

我在下面编造了一个制作例子。我不会解决下面的“人际关系”问题。但这是一个示例,用于显示我现有数据库中的内容。

问题是我从Person表中带回信息......但是基于关系表中的FK .....定义了(其他)人与我的关系。 (再次,这是一个组成的例子)

现在,我的现有查询“扁平化”数据,有很多LEFT连接。 Aka,我每人有4列数据,我现有的查询有20列(4列x 5人类型)....带别名列名。 “MotherLastName,MotherFirstName,MotherCreateDate”等等。

有没有办法在一个结果中将所有5行带回UNION ALL以外的所有内容。

可能没有,但我是C#开发人员,而不是TSQL超级大师。

如果最有效的话,我也可以带回5个结果(第一次尝试)。但我不认为是这种情况。

无论如何......只是一些星期五的思考 - 坦克。

感谢任何提示。

-- START TSQL

SET NOCOUNT ON


IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[PersonSpecialPeople]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) 
BEGIN 
DROP TABLE [dbo].[PersonSpecialPeople] 
END 
GO


IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[Person]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) 
BEGIN 
DROP TABLE [dbo].[Person] 
END 






CREATE TABLE [dbo].[Person] ( 

    [PersonUUID] [uniqueidentifier] NOT NULL,
    [LastName] [varchar](64) NOT NULL,
    [FirstName] [varchar](64) NOT NULL,
    [CreateDate] [datetime] NOT NULL
    )

GO

ALTER TABLE dbo.Person ADD CONSTRAINT PK_Person PRIMARY KEY NONCLUSTERED (PersonUUID) 
GO




IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[PersonSpecialPeople]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) 
BEGIN DROP TABLE [dbo].[PersonSpecialPeople] 
END 
GO

CREATE TABLE [dbo].[PersonSpecialPeople] ( 
      [PersonSpecialPeopleSurrogateUUID] [uniqueidentifier] NOT NULL
    , [CreateDate] [datetime] NOT NULL
    , [MePersonUUID] [uniqueidentifier] NOT NULL
    , [BestFriendPersonUUID] [uniqueidentifier] NOT NULL
    , [SpousePersonUUID] [uniqueidentifier] NOT NULL
    , [FatherPersonUUID] [uniqueidentifier] NOT NULL
    , [MotherPersonUUID] [uniqueidentifier] NOT NULL

)


GO

ALTER TABLE dbo.PersonSpecialPeople ADD CONSTRAINT PK_PersonSpecialPeople PRIMARY KEY NONCLUSTERED (PersonSpecialPeopleSurrogateUUID) 
GO

ALTER TABLE [dbo].[PersonSpecialPeople] ADD CONSTRAINT FK_ESP_MePersonUUID_To_PersonUUID FOREIGN KEY ([MePersonUUID]) REFERENCES dbo.Person (PersonUUID) 
GO

ALTER TABLE [dbo].[PersonSpecialPeople] ADD CONSTRAINT FK_ESP_BestFriendPersonUUID_To_PersonUUID FOREIGN KEY (BestFriendPersonUUID) REFERENCES dbo.Person (PersonUUID) 
GO

ALTER TABLE [dbo].[PersonSpecialPeople] ADD CONSTRAINT FK_ESP_SpousePersonUUID_To_PersonUUID FOREIGN KEY ([SpousePersonUUID]) REFERENCES dbo.Person (PersonUUID) 
GO

ALTER TABLE [dbo].[PersonSpecialPeople] ADD CONSTRAINT FK_ESP_FatherPersonUUID_To_PersonUUID FOREIGN KEY ([FatherPersonUUID]) REFERENCES dbo.Person (PersonUUID) 
GO

ALTER TABLE [dbo].[PersonSpecialPeople] ADD CONSTRAINT FK_ESP_MotherPersonUUID_To_PersonUUID FOREIGN KEY ([MotherPersonUUID]) REFERENCES dbo.Person (PersonUUID) 
GO


declare @PersonUUID_Me [uniqueidentifier]
select @PersonUUID_Me = '11111111-1111-1111-1111-111111111111'

declare @PersonUUID_BestFriend [uniqueidentifier]
select @PersonUUID_BestFriend = '44444444-4444-4444-4444-444444444444'
declare @PersonUUID_Spouse [uniqueidentifier]
select @PersonUUID_Spouse = '55555555-5555-5555-5555-555555555555'
declare @PersonUUID_Father [uniqueidentifier]
select @PersonUUID_Father = '77777777-7777-7777-7777-777777777777'
declare @PersonUUID_Mother [uniqueidentifier]
select @PersonUUID_Mother = '88888888-8888-8888-8888-888888888888'

INSERT INTO [dbo].[Person] (    [PersonUUID] , [LastName] , [FirstName] , [CreateDate] )
    Select @PersonUUID_Me , 'Coder', 'Granada' , CURRENT_TIMESTAMP
    UNION ALL Select @PersonUUID_BestFriend , 'Stephenson', 'Leo' , CURRENT_TIMESTAMP
    UNION ALL Select @PersonUUID_Spouse , 'Matheas', 'Mandie' , CURRENT_TIMESTAMP
    UNION ALL Select @PersonUUID_Father , 'Coder', 'Daddy' , CURRENT_TIMESTAMP
    UNION ALL Select @PersonUUID_Mother , 'Coder', 'Mommy' , CURRENT_TIMESTAMP

INSERT INTO [dbo].[PersonSpecialPeople] ( 
      [PersonSpecialPeopleSurrogateUUID] 
    , [CreateDate] 
    , [MePersonUUID]
    , [BestFriendPersonUUID] 
    , [SpousePersonUUID] 
    , [FatherPersonUUID] 
    , [MotherPersonUUID] )
Select NEWID() , CURRENT_TIMESTAMP , @PersonUUID_Me , @PersonUUID_BestFriend , @PersonUUID_Spouse , @PersonUUID_Father , @PersonUUID_Mother 



/* Version One, Get 1 Result per Person "Type" */

Select  [PersonUUID] , [LastName] , [FirstName] , [CreateDate] from [dbo].[Person] per
    where per.PersonUUID = @PersonUUID_Me

Select  [PersonUUID] , [LastName] , [FirstName] , per.[CreateDate] from [dbo].[Person] per
    join [dbo].[PersonSpecialPeople] spec on per.PersonUUID = BestFriendPersonUUID 
    where spec.[MePersonUUID] = @PersonUUID_Me

Select  [PersonUUID] , [LastName] , [FirstName] , per.[CreateDate] from [dbo].[Person] per
    join [dbo].[PersonSpecialPeople] spec on per.PersonUUID = [SpousePersonUUID] 
    where spec.[MePersonUUID] = @PersonUUID_Me

Select  [PersonUUID] , [LastName] , [FirstName] , per.[CreateDate] from [dbo].[Person] per
    join [dbo].[PersonSpecialPeople] spec on per.PersonUUID = [FatherPersonUUID] 
    where spec.[MePersonUUID] = @PersonUUID_Me

Select  [PersonUUID] , [LastName] , [FirstName] , per.[CreateDate] from [dbo].[Person] per
    join [dbo].[PersonSpecialPeople] spec on per.PersonUUID = [MotherPersonUUID] 
    where spec.[MePersonUUID] = @PersonUUID_Me



/* Version Two, Get 1 Result , with Union-All, with a unique 'Tag' as first column */

Select  [Relationship] = 'Me' , [PersonUUID] , [LastName] , [FirstName] , [CreateDate] from [dbo].[Person] per
    where per.PersonUUID = @PersonUUID_Me
UNION ALL
Select  [Relationship] = 'BestFriend' ,     [PersonUUID] , [LastName] , [FirstName] , per.[CreateDate] from [dbo].[Person] per
    join [dbo].[PersonSpecialPeople] spec on per.PersonUUID = BestFriendPersonUUID 
    where spec.[MePersonUUID] = @PersonUUID_Me
UNION ALL
Select  [Relationship] = 'Spouse' ,     [PersonUUID] , [LastName] , [FirstName] , per.[CreateDate] from [dbo].[Person] per
    join [dbo].[PersonSpecialPeople] spec on per.PersonUUID = [SpousePersonUUID] 
    where spec.[MePersonUUID] = @PersonUUID_Me
UNION ALL
Select  [Relationship] = 'Father' ,     [PersonUUID] , [LastName] , [FirstName] , per.[CreateDate] from [dbo].[Person] per
    join [dbo].[PersonSpecialPeople] spec on per.PersonUUID = [FatherPersonUUID] 
    where spec.[MePersonUUID] = @PersonUUID_Me
UNION ALL
Select  [Relationship] = 'Mother' ,     [PersonUUID] , [LastName] , [FirstName] , per.[CreateDate] from [dbo].[Person] per
    join [dbo].[PersonSpecialPeople] spec on per.PersonUUID = [MotherPersonUUID] 
    where spec.[MePersonUUID] = @PersonUUID_Me

2 个答案:

答案 0 :(得分:1)

如果您想避开UNION,可以使用JOINCASE这样的结构:

首先创建一个关系表:

CREATE TABLE [rel] ([Relationship] varchar(20) NOT NULL PRIMARY KEY);
INSERT INTO [rel] VALUES('BestFriend'),('Spouse'),('Father'),('Mother');

然后您可以执行以下语句:

SELECT [rel].[Relationship], per.[PersonUUID], per.[LastName], per.[FirstName], per.[CreateDate]
  FROM [dbo].[Person] per
       CROSS JOIN [rel]
       JOIN [dbo].[PersonSpecialPeople] spec ON
            per.PersonUUID = 
            CASE [rel].[Relationship]
                 WHEN 'BestFriend' THEN  BestFriendPersonUUID
                 WHEN 'Spouse' THEN  SpousePersonUUID
                 WHEN 'Father' THEN  FatherPersonUUID
                 WHEN 'Mother' THEN  MotherPersonUUID
            END

这使用了这样的事实,即连接不需要使用简单的a.colA = b.colB条件,但您可以声明在条件中导致布尔值的任何内容。但是,大多数数据库优化器都更倾向于标准格式a.colA = b.colB的连接。

答案 1 :(得分:1)

选项1: 使用UNPIVOT(http://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx)结帐。这是一个示例,它只使用一个UNION ALL来获取基本人员,然后是所有关系:

declare @PersonUUID_Me [uniqueidentifier]
select @PersonUUID_Me = '11111111-1111-1111-1111-111111111111';


SELECT Relationship = 'Me', p.PersonUUID, p.LastName, p.FirstName, p.CreateDate
FROM dbo.Person p
WHERE p.PersonUUID = @PersonUUID_Me

UNION ALL 

SELECT Relationship = replace(unpvt.ReleationshipType, 'PersonUUID', ''), unpvt.RelPersonUUID, p.LastName, p.FirstName, unpvt.CreateDate
FROM 
(
    SELECT *
    FROM dbo.PersonSpecialPeople
    where MePersonUUID = @PersonUUID_Me
) sp
UNPIVOT (RelPersonUUID FOR ReleationshipType IN 
    ([BestFriendPersonUUID] 
    , [SpousePersonUUID] 
    , [FatherPersonUUID] 
    , [MotherPersonUUID] 
    ) 
) as unpvt
INNER JOIN dbo.Person p ON p.PersonUUID = unpvt.RelPersonUUID

方案2: 您还可以重新考虑规范化数据库结构以具有以下新表:RelationshipType,PersonRelationship和摆脱[PersonSpecialPeople]。如果这是我理解的现有应用程序,那很难做到。

CREATE TABLE dbo.RelationshipType(RelationshipTypeID int not null primary key identity, Relationship nvarchar(50) not null)
go

CREATE TABLE dbo.PersonRelationship(
    [PersonUUID] [uniqueidentifier] NOT NULL foreign key references dbo.Person(PersonUUID), 
    [RelPersonUUID] [uniqueidentifier] NOT NULL foreign key references dbo.Person(PersonUUID),
    RelationshipTypeID int not null foreign key references dbo.RelationshipType(RelationshipTypeID),
    CreateDate datetime not null
)
go

然后填充新表:

INSERT INTO dbo.RelationshipType(Relationship)
VALUES('BestFriend')
,('Spouse')
,('Father')
,('Mother')
;

INSERT INTO dbo.PersonRelationship(PersonUUID, RelPersonUUID, RelationshipTypeID, CreateDate)
VALUES(@PersonUUID_Me, @PersonUUID_BestFriend,1, current_timestamp)
,(@PersonUUID_Me, @PersonUUID_Spouse, 2, current_timestamp)
,(@PersonUUID_Me, @PersonUUID_Father,3, current_timestamp)
,(@PersonUUID_Me, @PersonUUID_Mother,4, current_timestamp)

最后添加了简化的select语句,不需要在新的RelationshipType中修改。注意:不要在实际生产代码中使用select *,单独列出每个列。

SELECT Relationship = cast('Me' as varchar(50)), p.* 
FROM dbo.Person p
where p.PersonUUID = @PersonUUID_Me

union all

select rt.Relationship, p.* 
from dbo.PersonRelationship r
inner join dbo.Person p on p.PersonUUID = r.RelPersonUUID
inner join dbo.RelationshipType rt on rt.RelationshipTypeID = r.RelationshipTypeID
where r.PersonUUID = @PersonUUID_Me