wybranie wierszy przy self join

0

Cześć,

Napotkałem na pewien problem przy pisaniu zapytania. Przykładowo tabela zawiera relację użytkowników do odbytych przez nich szkoleń. Wiem że szkoleń jest maksymalnie cztery.

Struktura tabeli:

UserTrainingId int
UserId int
TrainingId int
TrainingDate date

chciałbym mieć dane w takiej postaci:
[UserId] [Training1Id] [Training1Date] [Training2Id] [Training2Date] [Training3Id] [Training3Date] [Training4Id] [Training4Date]

Czyli po prostu Id użytkownika i informacje o szkoleniach jakie odbył, jeśli nie odbył danego szkolenia powinny pojawić się NULL'e

napisałem takie zapytanie:

  select *
  from
  (
	select  * from [TEST].[dbo].[UserTraining]
	where TrainingId=1
  ) ut1
  full join   (
	select  * from [TEST].[dbo].[UserTraining]
	where TrainingId=2
  ) ut2 on ut2.UserId = ut1.UserId
  full join   (
	select  * from [TEST].[dbo].[UserTraining]
	where TrainingId=3
  ) ut3 on ut3.UserId = ut1.UserId
  full join   (
	select  * from [TEST].[dbo].[UserTraining]
	where TrainingId=4
  ) ut4 on ut4.UserId = ut1.UserId

Ale nie jest ono dobre ze względu na złączenie. Wybiera zdecydowanie za dużo informacji, oraz jeśli użytkownik nie ma odbytego szkolenia o Id = 1, wówczas wstawiany jest NULL. Fakt robię select * więc na pewno będą wybierane inne kolumny niż podałem, ale z wylistowaniem kolumn sobie już poradzę. Większy mam problem ze złączeniami...

Proszę o pomoc, jakieś nakierowanie jak to zrobić? Może pivot byłby dobry?

0

Witam, jak nie pivotem (choć chyba byłby najzgrabniejszy tutaj) to może tak ...imho powinieneś użyć LEFT Joina - jeśli mówisz ze może nie być jakiegoś szkolenia dla użytkownika:

EDIT: Usunąłem póki co ... bo kawy nie wypiłem i bzdurę napisałem .... zaraz edytuje jak się obudzę.

Edit2: Troszkę się obudziłem Twój przerobiony kod zrobi robotę:

 SELECT ut.UserId,   ut1.TrainingId, ut1.TrainingDate,ut2.TrainingId, ut2.TrainingDate,
 ut3.TrainingId, ut3.TrainingDate, ut4.TrainingId, ut4.TrainingDate 
  FROM [TEST].[dbo].[UserTraining] ut

  LEFT JOIN   (
    SELECT  * FROM [TEST].[dbo].[UserTraining]
    WHERE TrainingId=1
  ) ut1 ON ut.UserId = ut1.UserId
  LEFT JOIN   (
    SELECT  * FROM [TEST].[dbo].[UserTraining]
    WHERE TrainingId=2
  ) ut2 ON ut.UserId = ut2.UserId
  LEFT JOIN   (
    SELECT  * FROM [TEST].[dbo].[UserTraining]
    WHERE TrainingId=3
  ) ut3 ON ut.UserId = ut3.UserId
  LEFT JOIN   (
    SELECT  * FROM [TEST].[dbo].[UserTraining]
    WHERE TrainingId=4
  ) ut4 ON ut.UserId = ut4.UserId

  GROUP BY ut.UserId,   ut1.TrainingId, ut1.TrainingDate,ut2.TrainingId, ut2.TrainingDate,
 ut3.TrainingId, ut3.TrainingDate, ut4.TrainingId, ut4.TrainingDate 
1

Dzięki za pomoc, w między czasie napisałem samemu używając pivot:

SELECT 
UserId
,[1] = MAX([1])
,[Training1] = MAX([TrainingPivot1])
,[2] = MAX([2])
,[Training2] = MAX([TrainingPivot2])
,[3] = MAX([3])
,[Training3] = MAX([TrainingPivot3])
,[4] = MAX([4])
,[Training4] = MAX([TrainingPivot4])
,[5] = MAX([5])
,[Training5] = MAX([TrainingPivot5])

FROM 
(
	SELECT 
	UserId
	, TrainingId
	, [TrainingDate]
	,'TrainingPivot' + CAST(TrainingId AS NVARCHAR) AS [TrainingDatePivot]
	FROM [TEST].[dbo].[UserTraining]
) p
PIVOT
(
	MAX (TrainingId)
	FOR TrainingId IN
	( [1], [2], [3], [4], [5] )
) AS pvt1
PIVOT
(
	MAX (TrainingDate)
	FOR TrainingDatePivot IN
	( [TrainingPivot1], [TrainingPivot2], [TrainingPivot3], [TrainingPivot4], [TrainingPivot5] )
) AS pvt2
Group By
	UserId
ORDER BY UserId;

Sam nie wiem czy lepsze jest to na joinach czy pivot :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1