Sql 在更新表变量的标识时,如何将表变量插入到具有标识列的表中?

Sql 在更新表变量的标识时,如何将表变量插入到具有标识列的表中?,sql,sql-server-2008,Sql,Sql Server 2008,我正在编写一个SQL脚本来为我们的数据库生成测试数据。我在表变量中生成数据(以便以后跟踪),然后将其插入到实际表中。问题是,我需要跟踪已添加到父表的行,以便稍后在脚本中生成其子数据。例如: CREATE TABLE Customer ( CustomerId INT IDENTITY, Name VARCHAR(50) ) CREATE TABLE Order ( OrderId INT IDENTITY, CustomerId INT,

我正在编写一个SQL脚本来为我们的数据库生成测试数据。我在表变量中生成数据(以便以后跟踪),然后将其插入到实际表中。问题是,我需要跟踪已添加到父表的行,以便稍后在脚本中生成其子数据。例如:

CREATE TABLE Customer (
    CustomerId INT IDENTITY,
    Name       VARCHAR(50)
)

CREATE TABLE Order (
    OrderId    INT IDENTITY,
    CustomerId INT,
    Product    VARCHAR(50)
)
因此,在我的脚本中,我创建了等效的表变量:

DECLARE @Customer TABLE (
    CustomerId INT IDENTITY,
    Name       VARCHAR(50)
) -- populate customers

DECLARE @Order TABLE (
    OrderId    INT IDENTITY,
    CustomerId INT,
    Product    VARCHAR(50)
) -- populate orders
我生成样本数据并将其插入到每个表变量中

现在,当我将客户从我的表变量插入到实际表中时,表变量中的
CustomerId
列将变得毫无意义,因为实际表的
CustomerId
列有自己的标识种子

在我的表变量中,有没有一种方法可以跟踪插入到实际表中的每一行的新标识,以便我可以对订单记录使用适当的
CustomerId
?或者,我有没有更好的办法


(注意:我最初使用一个应用程序生成测试数据,但在插入过程中运行太慢,因为需要生成超过1000000条记录。)

您可以使用光标将数据插入表中,并使用内置函数
SCOPE\u IDENTITY()
获取插入当前作用域的最后一个id(通过脚本)


请参阅,以了解有关如何首先从客户表中获取
MAX(CustomerId)
的更多信息。然后,我将去掉变量表上的
IDENTITY
列,并使用
ROW\u NUMBER()
和MaxCustomerId创建我自己的CustomerId。应该是这样的:

DECLARE @MaxCustomerId INT

SELECT @MaxCustomerId = ISNULL(MAX(CustomerId),0)
FROM Customer

DECLARE @Customer TABLE (
    CustomerId INT,
    Name       VARCHAR(50)
)

INSERT INTO @Customer(CustomerId, Name)
SELECT @MaxCustomerId + ROW_NUMBER() OVER(ORDER BY SomeColumn), Name
FROM YourDataTable
DECLARE @CustomerInputs TABLE (Name VARCHAR(50) ) 
DECLARE @CustomerOutputs TABLE (CustomerId INT ,Name VARCHAR(50) ) 

INSERT INTO CUSTOMERS (name)
    OUTPUT inserted.Customerid, inserted.Name  INTO  @CustomerOutputs
SELECT Name FROM @CustomerInputs

SELECT * from @CustomerOutputs 

或者在临时表中插入值,这样您就可以使用相同的ID填充订单表。

为什么需要表变量上的标识值?如果只使用int,则可以在插入完成后禁用ID。使用output子句获取它们。您可能需要一个“输入值”和“输出值”表varaiable来获得如下所示的结果:

DECLARE @MaxCustomerId INT

SELECT @MaxCustomerId = ISNULL(MAX(CustomerId),0)
FROM Customer

DECLARE @Customer TABLE (
    CustomerId INT,
    Name       VARCHAR(50)
)

INSERT INTO @Customer(CustomerId, Name)
SELECT @MaxCustomerId + ROW_NUMBER() OVER(ORDER BY SomeColumn), Name
FROM YourDataTable
DECLARE @CustomerInputs TABLE (Name VARCHAR(50) ) 
DECLARE @CustomerOutputs TABLE (CustomerId INT ,Name VARCHAR(50) ) 

INSERT INTO CUSTOMERS (name)
    OUTPUT inserted.Customerid, inserted.Name  INTO  @CustomerOutputs
SELECT Name FROM @CustomerInputs

SELECT * from @CustomerOutputs 

这里有一种方法。如果你能使用它取决于你的情况。当用户使用数据库时,不应在生产环境中执行此操作

-- Get the next identity values for Customer and Order
declare @NextCustomerID int
declare @NextOrderID int
set @NextCustomerID = IDENT_CURRENT('Customer')+1
set @NextOrderID = IDENT_CURRENT('Order')+1

-- Create tmp tables
create table #Customer (CustomerID int identity, Name varchar(50))
create table #Order (OrderID int identity, CustomerID int, Product varchar(50))

-- Reseed the identity columns in temp tables
dbcc checkident(#Customer, reseed, @NextCustomerID) 
dbcc checkident(#Order, reseed, @NextOrderID) 

-- Populate #Customer
-- Populate #Order

-- Allow insert to identity column on Customer
set identity_insert Customer on

-- Add rows to Customer
insert into Customer(CustomerId, Name)
select CustomerID, Name
from #Customer

-- Restore identity functionality on Customer
set identity_insert Customer off

-- Add rows to Order
set identity_insert [Order] on
insert into [Order](OrderID, CustomerID, Product)
select OrderID, CustomerID, Product
from #Order
set identity_insert [Order] off

-- Drop temp tables
drop table #Customer
drop table #Order

-- Check result
select * from [Order]
select * from Customer

我无法控制数据库模式;我将无法删除标识规范。@Adam Maras我的意思是仅在变量表中删除
identity
列,这样,如果在客户表中插入带有
ORDER BY CustomerId
子句的值,您应该获得与变量表上已有的Id相同的Id。使用游标生成测试数据是一个糟糕的主意。scope_identity()很好,但输出更好。哎哟,他想生成数百万行。你说得对,赫格姆!我还不知道
输出
。这与我提出的任何答案一样接近。我在嵌套循环中生成了数据(别管我,现在这只是一次性的事情),并使用
SCOPE\u IDENTITY
跟踪我在哪个父记录上。当您将订单移动到订单表时,如何将@customeroutput中的新id映射到@Order表中的旧id?如果名称是客户中的候选关键字,则可以使用名称作为查找。