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 に答える