0

我试图弄清楚是否有可能以这个表为例......

CustomersTable
 Id  | Name | Address
  1  | John | Street A
  2  | Paul | Street B
  3  | Mary | Street C

ContactsTable
 Id  | CustomerId | ContactName | Contact
  1  |     1      |  Contact A  |   123
  2  |     1      |  Contact B  |   543
  3  |     2      |  Contact 1  |   678
  4  |     3      |  Contact A1 |   980
  5  |     3      |  Contact B2 |   521

得到这样的东西......

 Id  |  Name  |  Address   | ContactId_1 | ContactName_1 | Contact_1 | ContactId_2 | ContactName_2 | Contact_2
  1  |  John  |  Street A  |      1      |   Contact A   |    123    |      2      |   Contact B   |    543
  2  |  Paul  |  Street B  |      3      |   Contact 1   |    678    |     NULL    |     NULL      |    NULL
  3  |  Mary  |  Street C  |      4      |   Contact A1  |    980    |      5      |   Contact B2  |    521

这个想法是获得一个表格,其中联系人与其所属的每个客户并排。并且联系人列联系人当然将取决于每个客户的联系人数量。

这可以做到吗?如何?

提前致谢!

4

2 回答 2

3

如果您知道要转换的列数,则可以使用anUNPIVOT和 a来完成此操作,那么您可以使用静态版本:PIVOT

select *
from
(
  select id, customerid, name, address,
    col + '_'+ cast(rn as varchar(10)) col,
    value
  from
  (
    select c.id, customerid, c.name, c.address,
      t.contactname,
      cast(t.contact as varchar(20)) contact, 
      cast(t.id as varchar(20)) contactid,
      row_number() over(partition by customerid order by customerid) rn
    from customers c
    left join contacts t
      on c.id = t.customerid
  ) x
  unpivot
  (
    value
    for col in (ContactName, Contact, ContactId)
  ) u
) x1
pivot
(
  min(value)
  for col in ([ContactId_1], [ContactName_1], [Contact_1],
              [ContactId_2], [ContactName_2], [Contact_2])
) p

SQL Fiddle with Demo

但是,如果您不知道一条记录将有多少联系人,那么我会使用动态 SQL 来执行此操作:

DECLARE @colsPivot AS NVARCHAR(MAX),
    @colsUnpivot AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)


SET @colsUnPivot = stuff((select ','
                      +quotename(case when C.name = 'id' then'ContactId' else c.name end)
         from sys.columns as C
         where C.object_id = object_id('contacts') and
               C.name <> 'CustomerId'
         for xml path('')), 1, 1, '')

SET @colsPivot 
  = stuff((select ','+quotename(case when C.name = 'id' then'ContactId' else c.name end + '_' + cast(rn as varchar(10)))
         from sys.columns as C
         cross apply
         ( 
           select row_number() over(partition by customerid order by customerid) rn
           from customers c
           left join contacts t
             on c.id = t.customerid
          ) x
         where C.object_id = object_id('contacts') and
               C.name <> 'CustomerId'
         group by name, rn
         order by rn
         for xml path('')), 1, 1, '')


set @query 
  = ' 
      select *
      from
      (
        select id, customerid, name, address,
          col + ''_''+ cast(rn as varchar(10)) col,
          value
        from 
        (
          select c.id, customerid, c.name, c.address,
            t.contactname,
            cast(t.contact as varchar(20)) contact, 
            cast(t.id as varchar(20)) contactid,
            row_number() over(partition by customerid order by customerid) rn
          from customers c
          left join contacts t
            on c.id = t.customerid
        ) x1
        unpivot 
        (
           value
           for col in (' + @colsUnPivot + ')
        ) unpvt 

      ) x2
      pivot
      (
        min(value)
        for col in(' + @colsPivot +')
      )p'

execute(@query)

SQL Fiddle with Demo

两者都产生相同的结果。

于 2012-09-12T13:11:27.600 回答
1

我首选的方式是加入和聚合。关键是为枢轴生成一个序列号:

select c.id, c.name, c.address,
       max(case when seqqnum = 1 then con.ContactId end) as ContactId_1,
       max(case when seqqnum = 1 then con.ContactName end) as ContactName_1,
       max(case when seqqnum = 1 then con.Contact end) as Contact_1,
       max(case when seqqnum = 2 then con.ContactId end) as ContactId_2,
       max(case when seqqnum = 2 then con.ContactName end) as ContactName_2,
       max(case when seqqnum = 2 then con.Contact end) as Contact_2
from customers c join
     (select con.*,
             row_number() over (partition by customerId order by id) as seqnum
      from contacts con
     ) con
     on c.id = con.customerid
group by c.id, c.name, c.address

您也可以通过一系列连接来做到这一点,但我更喜欢这种方法。

于 2012-09-12T13:10:51.583 回答