Преобразование данных из множества записей в одну запись на сервере SQL - PullRequest
0 голосов
/ 18 марта 2012

Мне нужно преобразовать несколько похожих записей в одну запись. Может быть до 10 строк, которые необходимо объединить. Каждая группа строк, которые нужно объединить, имеет одинаковый идентификатор. И значения данных строки не имеют значения (на самом деле это GUID). Данные выглядят так:

Таблица A

ID    C1   C2    C3  
ID1   x    x     x  
ID1   y    y     y  
ID2   y    y     y  
ID2   x    x     x  
ID2   y    y     y  
ID2   y    y     y  
ID3   x    x     x  
ID3   y    y     y  
ID3   y    y     y  

Мне нужно преобразовать в эту структуру и иметь только одну запись для каждого идентификатора. Может быть N столбцов в зависимости от количества записей с одинаковым идентификатором (около 10).

Таблица B

ID     C1     C2     C3     C1A     C2A     C3A     C1B     C2B     C3B
ID1    x      x      x      y       y       y       null    null    null
ID2    y      y      y      x       x       x       y       y       y
ID3    x      x      x      y       y       y       y       y       y

Я не могу изменить таблицу B вообще. Просто объедините или вставьте его.
Я использую SQL Server 2008 R2, и объем таблицы A составляет около миллиона записей.
Любая помощь очень ценится.

ОБНОВЛЕНИЕ: добавление реальных определений таблиц.

Вот скрипт создания TableA:

SET ANSI_NULLS ON
    GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[IntervalPivotTable](
    [UID] [uniqueidentifier] NOT NULL,
    [ServiceHash] [int] NULL,
    [IntervalID] [nvarchar](50) NULL,
    [IntervalTypeID] [nvarchar](50) NULL,
    [IntervalGroupID] [nvarchar](50) NULL,
    [DrivingConditionID] [nvarchar](50) NULL,
 CONSTRAINT [PK_IntervalPivotTable] PRIMARY KEY CLUSTERED 
(
    [UID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  =     ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[IntervalPivotTable] ADD  CONSTRAINT [DF_IntervalPivotTable_UID]  DEFAULT         (newid()) FOR [UID]
GO

Вот скрипт создания TableB: SET ANSI_NULLS ON GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[PivotedIntervals](
    [ServiceHash] [int] NULL,
    [IntervalID_0] [nvarchar](50) NULL,
    [IntervalTypeID_0] [nvarchar](50) NULL,
    [IntervalGroupID_0] [nvarchar](50) NULL,
    [DrivingConditionID_0] [nvarchar](50) NULL,
    [IntervalID_1] [nvarchar](50) NULL,
    [IntervalTypeID_1] [nvarchar](50) NULL,
    [IntervalGroupID_1] [nvarchar](50) NULL,
    [DrivingConditionID_1] [nvarchar](50) NULL,
    [IntervalID_2] [nvarchar](50) NULL,
    [IntervalTypeID_2] [nvarchar](50) NULL,
    [IntervalGroupID_2] [nvarchar](50) NULL,
    [DrivingConditionID_2] [nvarchar](50) NULL,
    [IntervalID_3] [nvarchar](50) NULL,
    [IntervalTypeID_3] [nvarchar](50) NULL,
    [IntervalGroupID_3] [nvarchar](50) NULL,
    [DrivingConditionID_3] [nvarchar](50) NULL,
    [IntervalID_4] [nvarchar](50) NULL,
    [IntervalTypeID_4] [nvarchar](50) NULL,
    [IntervalGroupID_4] [nvarchar](50) NULL,
    [DrivingConditionID_4] [nvarchar](50) NULL,
    [IntervalID_5] [nvarchar](50) NULL,
    [IntervalTypeID_5] [nvarchar](50) NULL,
    [IntervalGroupID_5] [nvarchar](50) NULL,
    [DrivingConditionID_5] [nvarchar](50) NULL,
    [IntervalID_6] [nvarchar](50) NULL,
    [IntervalTypeID_6] [nvarchar](50) NULL,
    [IntervalGroupID_6] [nvarchar](50) NULL,
    [DrivingConditionID_6] [nvarchar](50) NULL,
    [IntervalID_7] [nvarchar](50) NULL,
    [IntervalTypeID_7] [nvarchar](50) NULL,
    [IntervalGroupID_7] [nvarchar](50) NULL,
    [DrivingConditionID_7] [nvarchar](50) NULL,
    [IntervalID_8] [nvarchar](50) NULL,
    [IntervalTypeID_8] [nvarchar](50) NULL,
    [IntervalGroupID_8] [nvarchar](50) NULL,
    [DrivingConditionID_8] [nvarchar](50) NULL,
    [IntervalID_9] [nvarchar](50) NULL,
    [IntervalTypeID_9] [nvarchar](50) NULL,
    [IntervalGroupID_9] [nvarchar](50) NULL,
    [DrivingConditionID_9] [nvarchar](50) NULL,
    [IntervalID_10] [nvarchar](50) NULL,
    [IntervalTypeID_10] [nvarchar](50) NULL,
    [IntervalGroupID_10] [nvarchar](50) NULL,
    [DrivingConditionID_10] [nvarchar](50) NULL 
) ON [PRIMARY]

GO

1 Ответ

3 голосов
/ 18 марта 2012

Возможно, вы захотите попробовать комбинацию unpivot / pivot . Unpivot преобразует TableA в строки только с тремя столбцами, id, ColumnID и guid, например

ID1, C1_0, x
ID1, C2_0, x
ID1, C3_0, x
ID1, C1_1, x
ID1, C2_1, x
ID1, C3_1, x

добавление уникального номера к каждой комбинации id / столбца (row_number over (...)) и делает это для каждой строки в TableA. Pivot преобразует их в один ряд по id:

select *
from
(
  select id, 
         code 
         + '_' 
         + convert(varchar(10), ColumnID) - 1 ColumnID,
         guid
  from 
  (
    select TableA.*,
           row_number() over (partition by ID
                              order by TableA_PK) - 1 ColumnID
      from TableA
  )
  unpivot
  (
    guid for code in (c1, c2, c3)
  ) as u
) UnpivotedTable
pivot
(
  min(guid)
  for columnid in ([c1_0], [c2_0], [c3_0], [c1_1], [c2_1], [c3_1])
) PivotedTable

Не пугайтесь присутствия мин (гид). Именно здесь, потому что стержень настаивает на агрегатной функции. Поскольку для каждой комбинации ID / ColumnID существует только один идентификатор guid, пропущенных значений не будет. Для проверки замените min (guid) на count (guid) и проверьте значения больше 1.

ОБНОВЛЕНИЕ: чтобы избежать смешивания разных строк из одного и того же идентификатора, мне пришлось изменить порядок по выражению row_number () на порядок по первичному ключу TableA. Если в таблице нет PK, необходимо преобразовать ввод так, чтобы он включал row_number () в качестве суррогатного первичного ключа:

(
       select TableA.*, row_number() over (order by ID) TableA_PK
         from TableA
) TableAWithAPrimaryKey

и использовать производную таблицу вместо исходной таблицы.

ОБНОВЛЕНИЕ 2:

Моя ошибка заключалась в размещении row_number () в невыбранный выбор. Номера строк для идентификатора должны быть извлечены до преобразования, очевидно. Это сводная таблица, которая использует оригинальные таблицы:

select *
from
(
  select ServiceHash, 
         code 
         + '_' 
         + convert(varchar(10), ColumnID) ColumnID,
         guid
  from 
  (
    select IntervalPivotTable.*,
           row_number() over (partition by ServiceHash 
                            order by UID) - 1 ColumnID
      from IntervalPivotTable
  ) a
  unpivot
  (
    guid for code in 
    (
      IntervalID,
      IntervalTypeID,
      IntervalGroupID,
      DrivingConditionID
    )
  ) as u
) UnpivotedTable
pivot
(
  min(guid)
  for columnid in 
  (
    IntervalID_0,
    IntervalTypeID_0,
    IntervalGroupID_0,
    DrivingConditionID_0,
    IntervalID_1,
    IntervalTypeID_1,
    IntervalGroupID_1,
    DrivingConditionID_1,
    IntervalID_2,
    IntervalTypeID_2,
    IntervalGroupID_2,
    DrivingConditionID_2
 -- Continue list of pivoted columns up to _10 here
  )
) PivotedTable
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...