拆分表并插入带有标识链接

时间:2010-06-16 06:57:15

标签: sql-server sql-server-2005 identity-column

我有3张类似于下面结构的表格

    CREATE TABLE [dbo].[EmpBasic](
        [EmpID] [int] IDENTITY(1,1) NOT NULL Primary Key,
        [Name] [varchar](50),
        [Address] [varchar](50)
        )


    CREATE TABLE [dbo].[EmpProject](
        [EmpID] [int] NOT NULL primary key,  // referencing column with EmpBasic
        [EmpProject] [varchar](50)  )



    CREATE TABLE [dbo].[EmpFull_Temp](
        [ObjectID] [int] IDENTITY(1,1) NOT NULL Primary Key,
        [T1Name] [varchar](50) ,
        [T1Address] [varchar](50) ,
        [T1EmpProject] [varchar](50) 
            )

EmpFull_Temp表包含带有虚拟对象ID列的记录...我想用前面的表中的记录填充前2个表...但是使用EmpID作为前2个表之间的引用。

我在存储过程中尝试过这个...

    Create Table #IDSS (EmpID bigint, objID bigint)

    Insert into EmpBasic
        output Inserted.EmpID, EmpFull_Temp.ObjectID
        into #IDSS
        Select T1Name, T1Address from EmpFull_Temp
            Where ObjectID < 106


    Insert into EmpProject
        Select A.EmpID, B.T1EmpProject from #IDSS as A, EmpFull_Temp as B
            Where A.ObjID = B.ObjectID

但它说..无法绑定多部分标识符“EmpFull_Temp.ObjectID”。

你能帮助我实现这个目标吗?

编辑:无法保证[EmpBasic]表中的[名称] + [地址]是唯一的

4 个答案:

答案 0 :(得分:2)

使用您的EmpProject连接表,您可能不希望上的主键约束 EmpID列

DECLARE @Count          int
DECLARE @NextEmpID      int
DECLARE @StartObjectID  int
DECLARE @EndObjectID    int

-- range of IDs to transfer (inclusive)
SET @StartObjectID  = 1
SET @EndObjectID    = 105

BEGIN TRAN
    -- lock tables so IDENT_CURRENT is valid
    SELECT @Count = COUNT(*) FROM [EmpBasic] WITH (TABLOCKX, HOLDLOCK)
    SELECT @Count = COUNT(*) FROM [EmpProject] WITH (TABLOCKX, HOLDLOCK)

    SELECT @NextEmpID = IDENT_CURRENT('EmpBasic') 

    SET IDENTITY_INSERT [EmpBasic] ON
    INSERT [EmpBasic] ([EmpID], [Name], [Address])
    SELECT @NextEmpID + ROW_NUMBER() OVER(ORDER BY ObjectID), [T1Name], [T1Address]
    FROM [EmpFull_Temp]
    WHERE [ObjectID] BETWEEN @StartObjectID AND @EndObjectID
    SET IDENTITY_INSERT [EmpBasic] OFF

    INSERT [EmpProject]([EmpID], [EmpProject])
    SELECT @NextEmpID + ROW_NUMBER() OVER(ORDER BY ObjectID), [T1EmpProject]
    FROM [EmpFull_Temp]
    WHERE [ObjectID] BETWEEN @StartObjectID AND @EndObjectID

COMMIT TRAN

答案 1 :(得分:1)

此问题的解决方案取决于“父”表(即具有IDENTITY列的表)是否具有自然键(即一个或多个字段,当组合时,保证是唯一的,其他而不是代理主键)。

例如,在这种情况下,名称和地址的组合是唯一的吗?

如果答案是肯定的,那么您可以简单地插入到EmpBasic中,而无需输出和存储生成的ID。然后,您可以使用自然键(例如名称和地址)插入到EmpProject中,重新连接到EmpBasic,以获得正确的EmpID。

Insert into EmpBasic 
    Select T1Name, T1Address from EmpFull_Temp 
        Where ObjectID < 106 

Insert into EmpProject 
    Select A.EmpID, B.T1EmpProject from EmpBasic as A, EmpFull_Temp as B 
        Where A.Name = B.Name And A.Address = B.Address

如果答案是否定的话,我知道没有简单的解决方案 - 在SQL Server 2005中(我不知道2008年是否有任何不同),不可能输出未插入的值。我过去通过使用其他字段之一(例如Name)来暂时存储原始ID(在本例中为ObjectID),在插入子记录时使用它来加入,如上所述然后消失返回更新父记录o删除/替换临时值。这不好,但我找不到更好的方法。

Insert into EmpBasic 
    Select cast(ObjectID as varchar(50)) as name, T1Address from EmpFull_Temp 
        Where ObjectID < 106 

Insert into EmpProject 
    Select A.EmpID, B.T1EmpProject from EmpBasic as A, EmpFull_Temp as B 
        Where A.Name = cast(B.ObjectID as varchar(50))

Update EmpBasic 
    Set Name = B.T1Name
    from EmpBasic as A, EmpFull_Temp as B 
        Where A.Name = cast(B.ObjectID as varchar(50))

请注意:我没有测试上面给出的示例SQL,但我希望它能让您了解如何处理这个问题。

答案 2 :(得分:1)

将一个ObjectID列添加到EmpBasic表以便于数据传输,然后在完成后将其删除。我假设这是一次性操作,如果正在进行,我不建议添加和删除列

答案 3 :(得分:1)

我使用Stack Exchange Data Explorer来研究替代解决方案。目前唯一有承诺的人是here。它实际上是@ScotHauder的答案,除了使用具有ObjectID列的临时表并使用IDENTITY_INSERT将生成的EmpId值移动到EmpBasic之外。

如果您必须多次执行此操作,则需要将EmpBasic_Temp EmpId IDENTITY起始值设为Max(EmpBasic.EmpID)+1