2015-09-15 6 views
2

У меня есть 3 таблицы:SQL Server Flatten Data

tUsers 
    -uid 

tColors 
    -colorid 
    -colorname 

tColors_User_Detail 
    -uid_fk 
    -colorid_fk 

Пользователи выбирают цвета, которые они любят, и только цвета, которые им нравятся. Это создает записи в tColors_User_Detail. Мне нужно сгладить это, чтобы каждый пользователь имел одну запись с цветом из tColors в качестве имени столбца, и они имеют значение True/False в строке для каждого цвета в зависимости от того, была ли у них запись в tColors_User_Detail. Если у пользователя не было цвета, выбранного в tColors_User_Detail, это будет False значение в конкретном столбце цвета. И, если у них есть запись в tColors_User_Detail для цвета, это будет истинное значение для соответствующего столбца цвета.

Любая помощь приветствуется.

+1

Не могли бы вы предоставить то, что вы уже пробовали? – Dane

+2

Также введите данные ввода и вывода данных с несколькими строками, чтобы объяснить желаемый результат. – Utsav

+0

Google - оператор PIVOT, или даже другие опорные решения. Они предназначены для того, чтобы делать то, что вы хотите. –

ответ

2

Вот пример PIVOT с COALESCE, чтобы показать «false», если значение не доступно. Это предполагает, что вам нужно жестко закодировать имена цветов для имен столбцов.

DECLARE @tUsers TABLE ([uid] INT) 
DECLARE @tColors TABLE ([colorid] INT, [colorname] VARCHAR(50)) 
DECLARE @tColors_User_Detail TABLE ([uid_fk] INT, [colorid_fk] INT) 
INSERT @tUsers VALUES (1),(2) 
INSERT @tColors VALUES (1,'Blue'),(2,'Red'),(3,'Green') 
INSERT @tColors_User_Detail VALUES (1,1),(1,2),(1,3),(2,1) 

SELECT 
    uid, 
    COALESCE([Red], 'False') AS [Red], 
    COALESCE([Blue], 'False') AS [Blue], 
    COALESCE([Green], 'False') AS [Green] 
FROM @tUsers U 
    LEFT OUTER JOIN @tColors_User_Detail CUD 
     ON CUD.uid_fk = U.uid 
    LEFT OUTER JOIN @tColors C 
     ON C.colorid = CUD.colorid_fk 
    PIVOT (MAX(colorname) FOR colorname IN (
     [Red], 
     [Blue], 
     [Green] 
    )) PVT 

Если вы хотите, чтобы столбцы были динамическими из цветов, вам нужно будет использовать динамический sql.

DECLARE @Sql VARCHAR(1000) = 
    'SELECT uid' 
    + (SELECT ', CASE WHEN [' + [colorname] + '] IS NOT NULL THEN ''True'' ELSE ''False'' END AS [' + [colorname] + ']' AS [text()] FROM tColors FOR XML PATH('')) 
    + ' FROM tUsers U 
      LEFT OUTER JOIN tColors_User_Detail CUD 
       ON CUD.uid_fk = U.uid 
      LEFT OUTER JOIN tColors C 
       ON C.colorid = CUD.colorid_fk 
      PIVOT (MAX(colorname) FOR colorname IN (' 
    + SUBSTRING((SELECT ',[' + [colorname] + ']' AS [text()] FROM tColors FOR XML PATH('')), 2, 1000) 
    + ')) PVT' 
EXEC (@Sql) 
+0

Спасибо. Да, мне нужны имена цветов, которые нужно вытащить из таблицы tColors, а не жестко закодированные, поскольку доступные цвета могут меняться со временем. – devnuts

+0

Просто обновлен с динамическим sql. –

+0

Спасибо, я посмотрю, что я могу с этим сделать. – devnuts

1

Какой вкус SQL?

Что-то вдоль линий: http://sqlfiddle.com/#!6/ec4e2

SELECT U.uid 
    , C.colorid 
    , C.colorname 
    , (CASE WHEN cud.uid_fk IS NOT NULL THEN 'True' ELSE 'False' END) AS ColorChosen 
FROM tUsers U 
FULL OUTER JOIN tColors C ON 1=1 
LEFT OUTER JOIN tColors_User_Detail cud ON 
    U.uid = cud.uid_fk 
    AND C.colorid = cud.colorID_FK 

EDIT: Я пропустил стержень для одной строки для каждого пользователя. Время встречи. Вернитесь немного.