我一直在努力适应基于SQL Server的基于集合的处理。下面是此任务的游标处理的简化版本。它涉及从购物车中的商品创建订单。创建订单,将订单项添加到订单详细信息表,累计并最终在订单表上更新。任何人都可以建议如何使用基于集合的方法而不是游标来做到这一点?
另一个问题是,在大多数情况下,光标一次最多可处理10个或12个订单项。这是否足以让我们不必考虑基于集合的方法?
declare getCart2 cursor for
select MemberID,ProductID,Quantity,Price
from Carts
where MemberID = @MemberID
open getCart2
fetch next from getCart2 into @MemberID,@ProductID,@Quantity,@Price
Insert into Orders
(MemberID,TotalAmount0
Values
(@MemberID, 0.00)
set @OrderID = @@Identity
while @@FETCH_STATUS = 0 Begin
Insert into OrderDetails
(OrderID,ProductID,Quantity)
Values
(@OderID,@ProductID,@Quantity)
set @TotalAmout = @TotalAmount + (@Quantity * @Price)
set @PrevMemberID = @MemberID
fetch next from getCart2 into @MemberID,@ProductID,@Quantity,@Price
End
close getCart2
deallocate getCart2
Update Orders
Set TotalAmount = @TotalAmount
Where OrderID = @OrderID
感谢您的帮助。
答案 0 :(得分:1)
这是一种方法:
在这种情况下,我正在创建一个临时表变量,用于存储订单ID。
然后,它在Order表上执行插入,然后在OrderDetails中执行。
最后,它计算TotalAmount并在Orders表上进行更新。
虽然您的代码(以及我的代码中)没有它,但我建议您在交易中使用此代码。
希望它可以帮助您提高绩效。
USE [tempdb];
GO
SET NOCOUNT ON;
IF OBJECT_ID(N'dbo.Carts', N'U') IS NOT NULL DROP TABLE [dbo].[Carts];
IF OBJECT_ID(N'dbo.Orders', N'U') IS NOT NULL DROP TABLE [dbo].[Orders];
IF OBJECT_ID(N'dbo.OrderDetails', N'U') IS NOT NULL DROP TABLE [dbo].[OrderDetails];
GO
-- Creates the tables like you have
CREATE TABLE [dbo].[Carts] (MemberID INT, ProductID INT, Quantity INT, Price DECIMAL(10, 2));
CREATE TABLE [dbo].[Orders] (OrderID INT IDENTITY(1, 1), MemberID INT, TotalAmount DECIMAL(10, 2));
CREATE TABLE [dbo].[OrderDetails] (OrderID INT, ProductID INT, Quantity INT);
-- Inserts dummy data
INSERT INTO [dbo].[Carts] VALUES (1001, 80, 5, 25.00);
INSERT INTO [dbo].[Carts] VALUES (1002, 120, 2, 12.90);
INSERT INTO [dbo].[Carts] VALUES (1010, 70, 3, 12.00)
INSERT INTO [dbo].[Carts] VALUES (1034, 176, 5, 45.00);
-- Temporary table that stores the inserted Order ID's
DECLARE @OrdersToProcess TABLE (OrderID INT, MemberID INT);
-- Inserts all Orders
INSERT INTO Orders (MemberID, TotalAmount)
OUTPUT inserted.OrderID, inserted.MemberID INTO @OrdersToProcess
SELECT MemberID, 0
FROM [dbo].[Carts]
-- Inserts order details
INSERT INTO OrderDetails (OrderID, ProductID, Quantity)
SELECT OrderID, ProductID, Quantity
FROM [dbo].[Carts] C
INNER JOIN @OrdersToProcess O ON C.MemberID = O.MemberID;
-- Updates order totals
UPDATE [dbo].[Orders]
SET TotalAmount = T.Total FROM
(
SELECT OrderID, SUM(Quantity * Price) AS [Total]
FROM [dbo].[Carts] C
INNER JOIN @OrdersToProcess O ON C.MemberID = O.MemberID
GROUP BY OrderID
) T
WHERE [dbo].[Orders].OrderID = T.OrderID
SELECT * FROM [dbo].[Orders];
SELECT * FROM [dbo].[OrderDetails];
答案 1 :(得分:0)
As I understand your problem, this store procedure should be called when a particular member presses the check-out button, so it should create a single order with all the items in the cart of that member.
You can use something like this:
INSERT INTO Orders (MemberID, TotalAmount)
VALUES (@MemberID, 0)
SET @OrderID=SCOPE_IDENTITY()
INSERT INTO OrderDetails (OrderID, ProductID, Quantity)
SELECT OrderID, ProductID, Quantity
FROM [dbo].[Carts] C
WHERE C.MemberID=@MemberID
UPDATE dbo.Orders SET TotalAmount=(
SELECT SUM(c.Quantity*c.Price)
FROM dbo.Carts c
WHERE c.MemberID=@MemberID
) WHERE OrderID=@OrderID
It's true that this reads the Carts
table twice, but with a proper index (on the MemberID
column) that should be fast enough.