我需要懂 SQL 的人的帮助,因为这是一个超出我 SQL 技能的问题。那是我的 table :
CREATE TABLE [dbo].[Orders]
(
id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
customerName VARCHAR(30) NOT NULL,
customerAddress VARCHAR(30) NOT NULL,
submitDate DATE NOT NULL,
realizationDate DATE,
deliveryTypeId INT NOT NULL
FOREIGN KEY(deliveryTypeId) REFERENCES deliveryTypes(id)
);
CREATE TABLE [dbo].[OrderItems]
(
id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
orderId INT NOT NULL,
productId INT NOT NULL,
productQuantity INT,
FOREIGN KEY(orderId) REFERENCES Orders(id),
FOREIGN KEY(productId) REFERENCES Products(id)
);
我需要创建一个存储过程,将一对多相关记录插入到数据库中的两个表中(事实上,这实际上是多对多绑定(bind)的一部分,但我只需要添加到这两个表中)。在我的应用程序 (.NET) 中,我需要传递一条记录“Orders”和一条或多条记录“OrderItems”。
我的问题是:
- 如果我插入“Order”,我将不知道在
OrderItems -> orderId
中设置什么值。我找到了SCOPE_IDENTITY
函数,但我真的不知道如何在我的案例中使用它。 - 如果我不知道有多少记录,如何在表中插入
OrderItems
记录?我只知道可以有一个或多个。 - 我不知道如何调用从应用程序级别接收许多
OrderItems
的过程以及我应该在存储过程中声明哪些参数
我真的很感谢所有的帮助,因为我面对这个问题已经有几个小时了,我真的不知道该怎么做。
编辑:这是我到目前为止想出的代码:
CREATE PROCEDURE spAddOrder
(@customerName VARCHAR(30),
@customerAddress VARCHAR(30),
@submitDate DATE,
@deliveryTypeId INT
-- I don't know how to pass many OrderItems rows as argument
)
AS
BEGIN
INSERT INTO Orders(customerName, customerAddress, submitDate, deliveryTypeId)
VALUES (@customerName, @customerAddress, @submitDate, @deliveryTypeId)
SELECT SCOPE_IDENTITY() AS orderId
-- I don't know how to do it for unknown number of rows
INSERT INTO OrderItems(orderId, productId, productQuantity)
VALUES (@orderId, @productId, @productQuantity)
END;
GO
最佳答案
虽然这个问题可能被认为过于宽泛,因此偏离主题,但它写得很好并且描述了许多没有经验的开发人员面临的问题 - 所以我认为它值得一个答案。
那么让我们把它分解成它的成分:
问:如何在插入后取回
identity
列的值?
答: SQL Server 提供了几种方法来做到这一点,最简单的可能是scope_identity
。 , 但最好是使用output
条款。问:如何将多行数据发送到存储过程?
答:使用table valued parameter .
现在让我们看看我们究竟要怎么做。
我们需要做的第一件事是创建一个用户定义的表类型以用于表值参数 - 所以:
CREATE TYPE [dbo].[Udt_OrderItems] AS TABLE
(
productId int NOT NULL,
productQuantity int,
);
GO
然后,我们可以使用此类型作为表值参数来创建存储过程。 我们还将订单详细信息作为标量参数发送到存储过程:
CREATE PROCEDURE stp_InsertOrderWithItems
(
@customerName varchar(30),
@customerAddress varchar(30),
@submitDate date,
@realizationDate date,
@deliveryTypeId int,
@orderItems dbo.Udt_OrderItems readonly -- Table valued parameters must be readonly
)
AS
DECLARE @Ids AS TABLE (orderId int NOT NULL) -- for the output clause
INSERT INTO dbo.Orders (customerName, customerAddress, submitDate, realizationDate, deliveryTypeId)
OUTPUT inserted.Id INTO @Ids
VALUES(@customerName, @customerAddress, @submitDate, @realizationDate, @deliveryTypeId)
INSERT INTO dbo.OrderItems (orderId, productId, productQuantity)
SELECT orderId, productId, productQuantity
FROM @orderItems
CROSS JOIN @Ids -- We only have one value in @Ids so cross join is safe
GO
至于 c# 部分,这取决于您如何连接到数据库 - 我将展示一个基本 ADO.Net 版本的示例:
using(var con = new SqlConnection(connectionString))
{
using(var cmd = new SqlCommand(con, "stp_InsertOrderWithItems"))
{
var dt = new DataTable()
dt.Columns.Add("productId", typeof(int));
dt.Columns.Add("productQuantity", typeof(int));
// populate data table here
cmd.Parameters.Add("@customerName", SqlDbType.VarChar, 30).Value = customerName;
// all the other scalar parameters here...
cmd.Parameters.Add(@orderItems, SqlDbType.Structured).Value = dt;
con.Open();
cmd.ExecuteNonQuery();
}
}
关于c# - 在存储过程中添加一条到多条记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53246406/