【问题标题】:Copy Rows with PK feedback loop使用 PK 反馈循环复制行
【发布时间】:2012-07-16 14:19:10
【问题描述】:

鉴于以下(表1):

Id    Field1  Field2     ...
--    ------  -------
NULL  1        2
NULL  3        4
...

我想将 Field1 和 Field2 的值插入到不同的表(Table2)中。 Table2 有一个自增整数主键。我想从 Table2 中检索新的 PK 并更新上面的 Id 列(Table1)。

我意识到这不是传统的 - 这不是我需要定期做的事情,只是一次性完成一些迁移工作。我使用INSERT INTO, OUTPUT, INSERTED.Id 进行了一些尝试,但失败了。 “环回”到 Table1 中的 PK 必须与插入的 Field1/Filed2 的值相关联。

【问题讨论】:

  • 每次插入 table2 后可能是“SELECT SCOPE_IDENTITY()”?
  • 您在 INSERT INTO / OUTPUT / Inserted.Id 尝试中使用了什么代码?你应该能够让它发挥作用。
  • Field1/Field2 是否生成唯一键?
  • Tim - 不,Field1/Field2 不能保证生成唯一键。所以必须有某种插入顺序的记忆。
  • mwigdahl - 插入 Table2(Field1,Field) OUTPUT Inserted.Id into Table1 从 Table1 中选择 Field1,Field2。各种各样的尝试

标签: sql sql-server-2005


【解决方案1】:

您应该能够进行插入,然后删除并重新插入。

create table t1
( id int, f1 int, f2 int);

create table t2
( id int primary key IDENTITY , f1 int, f2 int);

insert into t1 (id, f1, f2) values (null, 1, 2);    
insert into t1 (id, f1, f2) values (null, 3, 4);
insert into t1 (id, f1, f2) values (null, 5, 6);
insert into t1 (id, f1, f2) values (null, 5, 6);

insert into t2 (f1, f2) 
select f1, f2 from t1 where id is null;

delete t1 
  from t1 join t2 on (t1.f1 = t2.f1 and t1.f2 = t2.f2);

insert into t1
select id, f1, f2 from t2;

select * from t1;

SQLFiddle 上查看此示例。

【讨论】:

  • 问题是我的字段没有创建一组唯一的值。即使他们这样做了,我也必须索引所有这些。想象一个有很多字段的大表。这是否排除了你的答案?
  • @SFun28 - 你说'Field1'和'Field2'的组合不是唯一的,但就数据库而言,它们是相同的。我想您将不得不删除“重复”行,因为您无法将它们识别为与任何其他匹配行不同。
  • @SFun28 您不必为所有这些建立索引 - 在这种情况下,完全扫描可能会更好,因为您将记录从一个表加载到另一个表并过滤所有列。多个索引扫描会很慢,一次完整扫描就可以了。如果您的字段不是唯一的,您可以尝试插入记录,然后从表 1 中删除并重新插入。我会更新我的答案。
【解决方案2】:

您将需要某种类型的唯一键来匹配每个表中的行。我冒昧地为您的每个表添加了一个 TempGuid 列(您以后可以删除):

-- Setup test data
declare @Table1 table (
      Id int null
    , Field1 int not null
    , Field2 int not null
    , TempGuid uniqueidentifier not null unique
)
insert into @Table1 (Field1, Field2, TempGuid) select 1, 2, newid()
insert into @Table1 (Field1, Field2, TempGuid) select 3, 4, newid()

declare @Table2 table (
      Id int not null primary key identity(1, 1)
    , Field1 int not null
    , Field2 int not null
    , TempGuid uniqueidentifier not null unique
)

-- Fill Table2
insert into @Table2 (Field1, Field2, TempGuid)
select Field1, Field2, TempGuid
from @Table1

-- Update Table1 with the identity values from Table2
update a
set a.Id = b.Id
from @Table1 a
    join @Table2 b on a.TempGuid = b.TempGuid

-- Show results
select * from @Table1

Output 如果您在 Table1 上已经有一个要插入到 Table2 中的唯一键,则将是可行的。您还可以在循环或游标中执行临时唯一键(可能再次使用 GUID)并一次处理一行,但这对我来说似乎更糟。

更新

这是要在您的表上运行的实际 SQL:

-- Add TempGuid columns
alter table Table1 add TempGuid uniqueidentifier null
update Table1 set TempGuid = newid()
alter table Table2 add TempGuid uniqueidentifier not null

-- Fill Table2
insert into Table2 (Field1, Field2, TempGuid)
select Field1, Field2, TempGuid
from Table1

-- Update Table1 with the identity values from Table2
update a
set a.Id = b.Id
from Table1 a
    join Table2 b on a.TempGuid = b.TempGuid

-- Remove TempGuid columns
alter table Table1 drop column TempGuid
alter table Table2 drop column TempGuid

【讨论】:

    【解决方案3】:

    假设您对架构定义具有完全控制权,请向 Table2 添加一个引用 Table1 主键的外键。
    执行数据插入:

    INSERT INTO Table2 (Field1, Field2, T1PK)
    SELECT Field1, Field2, PK FROM Table1
    

    然后回填Table1:

    UPDATE t1 SET Id = t2.PK
    FROM Table1 t1 INNER JOIN Table2 t2 ON t2.T1PK = t1.PK
    

    然后从Table2中删除多余的列(T1PK)。

    编辑:

    由于Table1 中没有PK,所以只需在Table1 中添加一个,使用它,然后将其放在末尾。

    例如...

    ALTER TABLE Table1 ADD COLUMN T1PK UNIQUEIDENTIFIER CONSTRAINT Table1_PK PRIMARY KEY DEFAULT NEWID();
    
    ALTER TABLE Table2 ADD COLUMN T1PK UNIQUEIDENTIFIER NULL
    
    INSERT INTO Table2 (Field1, Field2, T1PK)
    SELECT Field1, Field2, T1PK FROM Table1
    
    UPDATE t1 SET Id = t2.PK
    FROM Table1 t1 INNER JOIN Table2 t2 ON t2.T1PK = t1.T1PK
    
    ALTER TABLE Table1 DROP CONSTRAINT Table1_PK
    
    ALTER TABLE Table1 DROP COLUMN T1PK
    
    ALTER TABLE Table2 DROP COLUMN T1PK
    

    【讨论】:

    • 在他的示例中,表 1 没有主键 - ID 字段为空,他需要回填。
    【解决方案4】:

    这并不漂亮,但应该一次性完成。

    create table tableA
    (
    id int,
    field1 int,
    field2 int
    )
    
    create table tableB
    (
    id int identity(1,1),
    field1 int,
    field2 int
    )
    
    insert into tableA select NULL, 1, 2
    insert into tableA select NULL, 2, 3
    
    declare @field1_value int;
    declare @field2_value int;
    declare @lastInsertedId int;
    
    DECLARE tableA_cursor CURSOR FOR 
        select field1, field2 from tableA
    
        OPEN tableA_cursor
        FETCH NEXT FROM tableA_cursor INTO @field1_value, @field2_value 
    
        WHILE @@FETCH_STATUS = 0
        BEGIN
    
            insert into tableB select @field1_value, @field2_value
            set @lastInsertedId = (SELECT SCOPE_IDENTITY())
            update a
                set id = @lastInsertedId
                from tableA a
            where field1 = @field1_value
                and field2 = @field2_value
        print @field1_value
    
        FETCH NEXT FROM tableA_cursor 
        INTO @field1_value, @field2_value
        END
    CLOSE tableA_cursor
    DEALLOCATE tableA_cursor
    

    不存在检查:

    declare @field1_value int;
    declare @field2_value int;
    declare @lastInsertedId int;
    
    DECLARE tableA_cursor CURSOR FOR 
        select field1, field2 from tableA
    
        OPEN tableA_cursor
        FETCH NEXT FROM tableA_cursor INTO @field1_value, @field2_value 
    
        WHILE @@FETCH_STATUS = 0
        BEGIN
    
            IF NOT EXISTS    
                (
                    select * from tableB 
                    where field1 = @field1_value 
                    and field2 = @field2_value   
                )    
                BEGIN
                    insert into tableB 
                    select @field1_value, @field2_value
    
                    set @lastInsertedId = (SELECT SCOPE_IDENTITY())
    
                    update a
                        set id = @lastInsertedId
                        from tableA a
                    where field1 = @field1_value
                        and field2 = @field2_value
                END     
    
        FETCH NEXT FROM tableA_cursor 
        INTO @field1_value, @field2_value
        END
    CLOSE tableA_cursor
    DEALLOCATE tableA_cursor
    

    【讨论】:

    • 如果只需要插入tableA中唯一的组合,那么在插入之前,我们只需要加上“不存在”检查即可;我会将此变体添加到我的答案中。
    猜你喜欢
    • 1970-01-01
    • 2014-02-06
    • 1970-01-01
    • 2015-04-12
    • 1970-01-01
    • 2018-10-27
    • 2010-12-09
    • 1970-01-01
    • 2015-07-22
    相关资源
    最近更新 更多