2014-01-24 2 views
0

У меня есть таблица отношений, где есть 4 FK обратно в таблицу пользователей ..., которая «тегирует» определенных пользователей, которые делали определенные вещи на сущности.Множество FK в таблице отношений, возвращающие строки в одном результате, но присоединение к другому столбцу как FK

Я придумал приведенный ниже пример. Я бы не решил проблему «отношений людей», как показано ниже. Но это составленный пример, чтобы показать, что у меня есть в моей существующей базе данных.

Проблема в том, что я возвращаю информацию из таблицы Person ... но на основе FK в таблице отношений ..... определяет, как (другое) лицо связано со мной. (Опять же, это составленный пример)

Прямо сейчас мой существующий запрос «сглаживает» данные с большим количеством ЛЕВЫХ соединений. Aka, где у меня есть 4 столбца данных на человека, мой существующий запрос содержит 20 столбцов (4 столбца x 5 человек) ... с именами столбцов псевдонима. «MotherLastName, MotherFirstName, MotherCreateDate» и т. Д. И т. Д.

Есть ли способ вернуть все 5 строк в одном результате за пределы СОЮЗА ВСЕ, что я сделал ниже.

Может быть и не так, но я разработчик 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 
+0

Что не так с 'UNION ALL'? – FrankPl

+0

Ничего особенного. Как я уже сказал, это вопрос мозгового центра. Я не знал, есть ли какой-нибудь синтаксис JOIN. Я «за» UNION-ALL Solution ... это моя идея переработать этот запрос здесь на рабочем месте. – granadaCoder

ответ

1

Если вы хотите, чтобы избежать UNION, вы можете использовать JOIN и CASE конструкцию так:

Сначала создать отношения таблицы:

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 

Th использует тот факт, что для этого объединения не нужно использовать простое условие a.colA = b.colB, но вы можете указать все, что приводит к булевскому значению в условии. Однако большинство оптимизаторов баз данных больше настроены на объединение стандартной формы a.colA = b.colB.

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) 

И, наконец, упрощена оператор выбора, который не должен быть изменен в новом 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 
+0

Если бы я создал db, это был бы вариант 2. Спасибо за другой вариант. – granadaCoder

Смежные вопросы