You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server+Access前端:配送路线序号并发生成与修改方案咨询

解决方案:SQL Server端实现配送订单序号的并发安全生成与维护

针对你遇到的多用户并发添加订单时序号重复、VBA方案失效的问题,以下是基于SQL Server后端的完整解决方案,确保序号唯一、支持顺序调整,且完全规避并发冲突。

一、新增订单时自动生成唯一序号(并发安全)

核心思路是将序号生成逻辑放在SQL Server端,通过事务+行锁避免并发冲突。假设:

  • 车辆日记录表:VanDaily,字段VanDailyID(每日车辆唯一标识,如Van1-2023/01/01对应ID=1)
  • 订单表:SalesOrders,字段包括SalesOrderID(主键)、VanDailyID(关联车辆日记录)、RouteOrderSequence(配送序号,总部为0)、其他业务字段

创建新增订单存储过程

CREATE PROCEDURE dbo.AddSalesOrderWithRouteSequence
    @VanDailyID INT,
    -- 按需添加其他订单参数(如CustomerID、DeliveryAddress等)
    @NewSalesOrderID INT OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRANSACTION;

    DECLARE @NextSeq INT;

    -- 锁定当前车辆日的所有订单,防止并发会话获取相同的最大序号
    SELECT @NextSeq = ISNULL(MAX(RouteOrderSequence), 0) + 1
    FROM SalesOrders WITH (UPDLOCK, HOLDLOCK)
    WHERE VanDailyID = @VanDailyID;

    -- 插入新订单并生成序号
    INSERT INTO SalesOrders (VanDailyID, RouteOrderSequence /* 其他业务字段 */)
    VALUES (@VanDailyID, @NextSeq /* 对应参数值 */);

    SET @NewSalesOrderID = SCOPE_IDENTITY();

    COMMIT TRANSACTION;
END;

说明:UPDLOCK和HOLDLOCK会在事务期间锁定查询范围内的行,确保其他会话无法修改/插入同一车辆日的订单,彻底避免并发序号重复问题。

二、调整订单配送顺序(上下移动)

通过事务包裹序号交换操作,保证顺序调整的原子性,避免中间状态异常。

向上移动订单(序号减1)

CREATE PROCEDURE dbo.MoveOrderUp
    @SalesOrderID INT
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRANSACTION;

    DECLARE @CurrentSeq INT, @VanDailyID INT;

    -- 获取当前订单的序号和所属车辆日ID
    SELECT @CurrentSeq = RouteOrderSequence, @VanDailyID = VanDailyID
    FROM SalesOrders
    WHERE SalesOrderID = @SalesOrderID;

    -- 边界判断:第一个配送订单(序号=1)无法向上移动
    IF @CurrentSeq <= 1
    BEGIN
        RAISERROR('无法向上移动,已是第一个配送订单', 16, 1);
        ROLLBACK TRANSACTION;
        RETURN;
    END;

    -- 交换当前订单与上一个订单的序号
    UPDATE SalesOrders
    SET RouteOrderSequence = RouteOrderSequence + 1
    WHERE VanDailyID = @VanDailyID AND RouteOrderSequence = @CurrentSeq - 1;

    UPDATE SalesOrders
    SET RouteOrderSequence = @CurrentSeq - 1
    WHERE SalesOrderID = @SalesOrderID;

    COMMIT TRANSACTION;
END;

向下移动订单(序号加1)

CREATE PROCEDURE dbo.MoveOrderDown
    @SalesOrderID INT
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRANSACTION;

    DECLARE @CurrentSeq INT, @VanDailyID INT, @MaxSeq INT;

    SELECT @CurrentSeq = RouteOrderSequence, @VanDailyID = VanDailyID
    FROM SalesOrders
    WHERE SalesOrderID = @SalesOrderID;

    -- 获取当前车辆日的最大序号
    SELECT @MaxSeq = MAX(RouteOrderSequence)
    FROM SalesOrders
    WHERE VanDailyID = @VanDailyID;

    -- 边界判断:最后一个配送订单无法向下移动
    IF @CurrentSeq >= @MaxSeq
    BEGIN
        RAISERROR('无法向下移动,已是最后一个配送订单', 16, 1);
        ROLLBACK TRANSACTION;
        RETURN;
    END;

    -- 交换当前订单与下一个订单的序号
    UPDATE SalesOrders
    SET RouteOrderSequence = RouteOrderSequence - 1
    WHERE VanDailyID = @VanDailyID AND RouteOrderSequence = @CurrentSeq + 1;

    UPDATE SalesOrders
    SET RouteOrderSequence = @CurrentSeq + 1
    WHERE SalesOrderID = @SalesOrderID;

    COMMIT TRANSACTION;
END;

三、异常修复:重新整理序号连续性

若出现手动修改序号导致的重复/断层问题,可通过以下存储过程重新生成连续序号:

CREATE PROCEDURE dbo.ResequenceOrdersForVanDaily
    @VanDailyID INT
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRANSACTION;

    -- 按原序号排序,重新生成连续的配送序号
    WITH OrderedOrders AS (
        SELECT SalesOrderID,
               ROW_NUMBER() OVER (ORDER BY RouteOrderSequence) AS NewSeq
        FROM SalesOrders
        WHERE VanDailyID = @VanDailyID
    )
    UPDATE SalesOrders
    SET RouteOrderSequence = oo.NewSeq
    FROM SalesOrders so
    JOIN OrderedOrders oo ON so.SalesOrderID = oo.SalesOrderID;

    COMMIT TRANSACTION;
END;

四、Access前端集成

在Access中通过ADO调用SQL Server存储过程,替代原VBA逻辑:

' 示例:新增订单
Sub AddNewSalesOrder(VanDailyID As Integer)
    Dim conn As ADODB.Connection
    Dim cmd As ADODB.Command
    Dim newOrderID As Integer

    Set conn = New ADODB.Connection
    conn.Open "你的SQL Server连接字符串" ' 示例:"Provider=SQLOLEDB;Data Source=服务器名;Initial Catalog=数据库名;User ID=账号;Password=密码;"

    Set cmd = New ADODB.Command
    cmd.ActiveConnection = conn
    cmd.CommandType = adCmdStoredProc
    cmd.CommandText = "dbo.AddSalesOrderWithRouteSequence"

    ' 添加参数
    cmd.Parameters.Append cmd.CreateParameter("@VanDailyID", adInteger, adParamInput, , VanDailyID)
    ' 按需添加其他业务参数
    cmd.Parameters.Append cmd.CreateParameter("@NewSalesOrderID", adInteger, adParamOutput)

    cmd.Execute

    newOrderID = cmd.Parameters("@NewSalesOrderID").Value
    MsgBox "新增订单ID:" & newOrderID

    conn.Close
    Set cmd = Nothing
    Set conn = Nothing
End Sub

上下移动按钮的逻辑类似,调用对应存储过程即可,捕获存储过程抛出的错误提示给用户。

内容的提问来源于stack exchange,提问作者Darren Oxley

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 18:05:29