将一个表的5列保存到不同表中的5行中

时间:2012-12-17 19:40:16

标签: sql sql-server sql-server-2008-r2 rows multiple-columns

我有一个表具有唯一ID的项:itemId,... 行的示例:'3506',...

我有一个包含以下列的表ItemProperties: itemId,datecreated,datemodified,property1,property2,property3,property4,property5

一行示例:'3506','2012 ...','2012 ...','prop1','prop2','prop3','prop4','prop5'

我需要将ItemProperties表的每一行拆分为NewItemProperties表中的5个单独的行,并包含以下列: itemId,datecreated,datemodified,propertynumber,property

5行的例子:

‘3506’, ‘2012…’, ‘2012…’, 1, ‘prop1’

‘3506’, ‘2012…’, ‘2012…’, 2, ‘prop2’

‘3506’, ‘2012…’, ‘2012…’, 3, ‘prop3’

‘3506’, ‘2012…’, ‘2012…’, 4, ‘prop4’

‘3506’, ‘2012…’, ‘2012…’, 5, ‘prop5’

约束: - 不应处理具有不再位于Items表中的itemId的ItemProperties

  • 此过程不应覆盖/更新NewItems表中的项(id = id和propertynumber = property1~5列的数量)

  • Microsoft SQL Server 2008 R2

  • ItemProperties表中的大约800000行

此刻我的解决方案非常缓慢:

...

DECLARE c CURSOR read_only FOR SELECT * from ItemProperties

DECLARE @ID varchar(14), @CREA datetime, …

OPEN  c     

FETCH NEXT FROM c INTO @ID, @CREA, @MODI, @COL, @SIZE, @PAT, @YEAR, @ITEM

WHILE (@@fetch_status <> -1)

BEGIN

    IF (@@fetch_status <> -2)

    BEGIN
         select * from Items where itemId = @ID
         if @@ROWCOUNT = 0
               BEGIN
                    GOTO Fetch_Next
               END
         select * from ItemProperties where itemId = @ID AND propertynumber = 1
         if @@ROWCOUNT = 0
               INSERT INTO NewItemProperties
               VALUES(@ID, '1', @COL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
         select * from ItemProperties where itemId = @ID AND propertynumber = 2
         if @@ROWCOUNT = 0
               INSERT INTO NewItemProperties
               VALUES(@ID, '2', @SIZE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
     …

      END
    Fetch_Next:
    FETCH NEXT FROM c INTO @ID, @CREA, @MODI, @COL, @SIZE, @PAT, @YEAR, @ITEM
...

我可以通过删除创建和修改日期来优化我的fetch语句,但这是我能想到的全部内容。我无法将其放入一个无法解析的查询中。基本上任何比光标更快的东西都会帮助我。欢迎所有想法。谢谢。

3 个答案:

答案 0 :(得分:2)

试试这个

INSERT INTO NewItemProperties
SELECT itemId, '1', property1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
FROM ItemProperties 
UNION ALL
SELECT itemId, '2', property2, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
FROM ItemProperties
......
UNION ALL
SELECT itemId, '5', property5, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
FROM ItemProperties

答案 1 :(得分:1)

我不确定为什么你说你无法让它适合UNPIVOT。但您应该能够使用UNPIVOT转换数据,然后将其插入新表中。您可以在内部查询中添加任何WHERE子句条件。 UNPIVOT的关键是数据具有相同的数据类型,因此如果需要,您可能必须将子查询中的数据转换为相同的数据类型:

insert into NewItemProperties(yourCcolsHere)
select itemid,
  datecreated, 
  datemodified,
  replace(col, 'property', '') col,
  value
from
(
 -- perform any datatype conversions here
  select i.itemid,
    p.datecreated,
    p.datemodified,
    p.property1, 
    p.property2, 
    p.property3, 
    p.property4, 
    p.property5
  from items i
  inner join ItemProperties p
    on i.itemid = p.itemid
) src
unpivot
(
  value
  for col in (property1, property2, property3,
              property4, property5)
) unpiv

请参阅SQL Fiddle with Demo

UNPIVOT函数执行与UNION ALL查询相同的功能:

insert into NewItemProperties(yourCcolsHere)
select i.itemid,
    p.datecreated,
    p.datemodified,
    1 PropNumber,
    p.property1 value 
from items i
inner join ItemProperties p
  on i.itemid = p.itemid
union all
select i.itemid,
    p.datecreated,
    p.datemodified,
    2 PropNumber,
    p.property2 value
from items i
inner join ItemProperties p
  on i.itemid = p.itemid -- add more queries for the other properties

请参阅SQL Fiddle with Demo

答案 2 :(得分:0)

我会通过定义一个返回要插入的所有内容然后插入它们的查询来完成此操作:

with toinsert as (
     select ip.itemid, datecreated, datemodified, num as propertynumber
            (case when num = 1 then property1
                  when num = 2 then property2
                  when num = 3 then property3
                  when num = 4 then property4
                  when num = 5 then property5
             ) as property
     from ItemProperties ip cross join
          (select 1 as num union all select 2 union all select 3 union all select 4 union all select 5
          ) nums left outer join
          NewItemProperties nip
          on ip.itemid = nip.itemid and
             nums.num = nip.propertynumber
     where nip.itemid is null
    )
insert into NewItemProperties (itemid, datecreated, datemodified, propertynumber, property)
    select *
    from toinsert