Вопрос, чтобы перечислить каждого ребенка делает запись в колонках родителя

Я нуждаюсь в опытной помощи. Я думал, что знал SQL вполне прилично, по крайней мере до этого пункта. Я работаю с SQL Server и потребностью построить вопрос, который перечисляет каждого зарегистрированного члена, и покажите каждое из имен их гостя (гостей) в отдельных колонках вместо рядов. У каждого участника могли быть 0:N гости, связанные с каждым участником. Так, Вот мои столы:

Таблица-участник: memberID (PK), FName, LName...

Стол гостя: GuestID (PK), FName, LastName...

Стол событий: GuestID (PK), MemberID (PK)...

Я пытаюсь построить продукцию вопроса как это:

MemberID | Member_FName | Member_LName | Guest1ID | Guest1_Fname | Guest2ID | Guest2_FName...

ОБРАЗЕЦ:

Member Table
MemberID | FName | LName
001        Frank   Smith   
002        Mary    Jane
003        John    Henry

Guest Table
GuestID | FName | LName
101       Steve   Smith
102       Peter   Smith
103       Mike    Jane

Event Table
MemberID | GuestID
001        101
001        102
002        103

ПРОДУКЦИЯ:

MemberID | FName | LName| GuestID1 | FName1 | LName1 |GuestID2 | FName2 | LName2
001        Frank   Smith  101        Steve    Smith   102        Peter    Smith
002        Mary    Jane   103        Mike     Jane
003        John    Henry

Пожалуйста, сообщите мне, должен ли я включать другую информацию.

заранее спасибо!

2
nl ja de
Следующая вещь к Google: "Первая Нормальная форма".
добавлено автор wildplasser, источник

2 ответы

Можно осуществить обоих UNPIVOT и затем ЦЕНТР функции, чтобы получить результаты. UNPIVOT берет ваши колонки и преобразовывает данные в ряды, и центр берет конечный результат и возвращает его в колонки:

select MemberID,
  memberfirst,
  memberlast,
  isNull(GuestId_1, '') GuestId_1, 
  isNull(fname_1, '') fname_1, 
  isNull(lname_1, '') lname_1,
  isNull(GuestId_2, '') GuestId_2, 
  isNull(fname_2, '') fname_2, 
  isNull(lname_2, '') lname_2
from
(
  select MemberID,
    memberfirst,
    memberlast,
    col+'_'+cast(rn as varchar(10)) col,
    value
  from
  (
    select m.MemberID,
      m.fname MemberFirst,
      m.lname MemberLast,
      isNull(cast(g.GuestID as varchar(5)), '') GuestId,
      isNull(g.fname, '') fname,
      isNull(g.lname, '') lname,
      row_number() over(partition by m.parentid order by g.guestid) rn
    from member m
    left join Event r
      on m.parentid = r.memberid
    left join guest g
      on r.guestid = g.guestid
  ) src
  unpivot
  (
    value
    for col in (GuestId, fname, lname)
  ) unpiv
) src1
pivot
(
  max(value)
  for col in (GuestId_1, fname_1, lname_1,
              GuestId_2, fname_2, lname_2)
) piv

See SQL Fiddle with Demo

Вышеупомянутое работает отлично, если вы знаете количество отчетов загодя, но если не тогда вы захотите использовать динамический sql:

DECLARE  @query  AS NVARCHAR(MAX),
    @colsPivot as  NVARCHAR(MAX),
    @colsPivotNull as  NVARCHAR(MAX)

select @colsPivot = STUFF((SELECT  ',' 
                      + quotename(c.name +'_'+ cast(t.rn as varchar(10)))
                    from
                    (
                      select cast(row_number() over(partition by m.MemberID order by g.guestid) as varchar(50)) rn
                      from member m
                      left join Event r
                        on m.parentid = r.memberid
                      left join guest g
                        on r.guestid = g.guestid
                    ) t
                    cross apply sys.columns as C
                   where C.object_id = object_id('guest')
                   group by c.name, t.rn
                   order by t.rn
            FOR xml PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

select @colsPivotNull = STUFF((SELECT  ', IsNull(' 
                      + quotename(c.name +'_'+ cast(t.rn as varchar(10)))+', '''') as '+c.name +'_'+ cast(t.rn as varchar(10))
                    from
                    (
                      select cast(row_number() over(partition by m.MemberID order by g.guestid) as varchar(50)) rn
                      from member m
                      left join Event r
                        on m.parentid = r.memberid
                      left join guest g
                        on r.guestid = g.guestid
                    ) t
                    cross apply sys.columns as C
                   where C.object_id = object_id('guest')
                   group by c.name, t.rn
                   order by t.rn
            FOR xml PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query 
  = 'select 
          MemberID,
          memberfirst,
          memberlast, '[email protected]+'
      from
      (
        select MemberID,
          memberfirst,
          memberlast,
          col+''_''+cast(rn as varchar(10)) col,
          value
        from 
        (
          select m.MemberID,
            m.fname MemberFirst,
            m.lname MemberLast,
            isNull(cast(g.GuestID as varchar(5)), '''') GuestId,
            isNull(g.fname, '''') fname,
            isNull(g.lname, '''') lname,
            row_number() over(partition by m.parentid order by g.guestid) rn
          from member m
          left join Event r
            on m.parentid = r.memberid
          left join guest g
            on r.guestid = g.guestid
        ) x
        unpivot
        (
         value
          for col in (GuestId, fname, lname)
        ) u
      ) x1
      pivot
      (
        max(value)
        for col in ('+ @colspivot +')
      ) p'

exec(@query)

See SQL Fiddle with Demo

Обе версии приводят к тому же самому результату:

| MemberID | MEMBERFIRST | MEMBERLAST | GUESTID_1 | FNAME_1 | LNAME_1 | GUESTID_2 | FNAME_2 | LNAME_2 |
-------------------------------------------------------------------------------------------------------
|        1 |       Frank |      Smith |       101 |   Steve |   Smith |       102 |   Peter |   Smith |
|        2 |        Mary |       Jane |       103 |    Mike |    Jane |           |         |         |
|        3 |        John |      Henry |           |         |         |           |         |         |
3
добавлено
@RussellPeters вы don' t должен UNPIVOT , что только необходимо обратиться ЦЕНТР . Контактная информация существует в другом столе?
добавлено автор Taryn, источник
Вышеупомянутый вопрос отвечают на ваш вопрос? Если так, затем, пожалуйста, рассмотрите принятие его как ответ через галочку налево от него. Это помогает будущим посетителям места знать ответ, который был выбран, и вы получаете представителя места его.
добавлено автор Taryn, источник
@RussellPeters видят эту скрипку - sqlfiddle.com/#! 3/f95f8/5
добавлено автор Taryn, источник
Возможно, необходимо отправить новый вопрос с новыми деталями. Это, вероятно, будет легче, чем движение назад и вперед на комментариях.
добавлено автор Taryn, источник
Спасибо за вашу помощь. Я думаю I' m почти там. На вопросе стороны этого I' проекта; m продолжающий работать, я надеялся, что можно посмотреть на этот код и сказать мне что I' m выполнение неправильно. Последние 3 колонки, предполагают, чтобы показать данные, но doesn' t sqlfiddle.com/#! 3/05d8b/1/0
добавлено автор Russell Peters, источник
просто отмеченный это как мой ответ!
добавлено автор Russell Peters, источник
Что я должен отредактировать на вопросе? sqlfiddle.com/#! 3/05d8b/1/0
добавлено автор Russell Peters, источник
Я вижу, что вы добавили новый стол, но почтовые данные о колонке, предполагают, чтобы показать данные из tbl_contactPreference' s область Descr. Я должен переименовать заголовок столбца вопроса, чтобы избежать беспорядка. Просто предположите, чтобы показать, кто согласился к каждому из типов коммуникации. ParentID | Добровольная рассылка | OptIn-телефон | OptIn-отправка-по-почте 001 почтовой Отправки по почте
добавлено автор Russell Peters, источник
Хорошо. Сделает, но первый пример ответил на вопросы. Просто имел несколько ошибок в нем. еще раз спасибо!!
добавлено автор Russell Peters, источник

На самом деле легче, чтобы сделать одну колонку для гостей и иметь список разделенных запятой значений.

Вы могли сделать это как это:

SELECT DISTINCT memberID, FName, LName, 
 STUFF((SELECT ', ' + FName + ' ' + LName + ' ('+GuestID+')'
  FROM Relationship R 
  JOIN Guest G ON R.GuestID = G.GuestID
  WHERE R.MemberID = Memeber.MemberID
  FOR xml PATH ('')),1,2,'') AS GuestList
FROM Member

Это было бы похоже на это:

MemberID | FName | LName| GuestList
001        Frank   Smith  Steve Smith (101), Peter Smith (102)
002        Mary    Jane   Mike Jane (103)
003        John    Henry
0
добавлено
SqlCom.ru - Стиль жизни SQL
SqlCom.ru - Стиль жизни SQL
908 участник(ов)

Правила чата - https://t.me/sqlcom/88269 @sqlcom - основной канал (только MS SQL) @sql_ninja - второй канал (SQL вопросы начального уровня и свободное общение) @Gopnegbot - Викторина по SQL Server (наберите в привате /quiz). Предложения в @sql_ninja

SQL_Ninja
SQL_Ninja
340 участник(ов)

Правила чата - https://t.me/sqlcom/88269 @sqlcom - основной канал (только SQL) @sql_ninja - второй канал (SQL вопросы начального уровня и свободное общение) @Gopnegbot - Викторина по SQL Server (наберите в привате /quiz)