出货收款金额分摊SQL处理方案

使用场景是销售出货收款分摊。一个销售单有多笔出货,针对这个销售单有多笔收款,数据处理需要将收款和出货关联在一起。

要求出货按时间排序,将不同时间的收款金额分别摊平到出货金额上,先出货的用最早一笔收款去摊平,该笔收款有余额则给下一笔出货使用,如果余额不足则使用下一笔收款继续摊平这笔出货,类推、,

当第一笔收款用尽,就用第二笔收款,第二笔收款用尽,用第三笔收款。计算出每笔出货中分摊的收款金额和收款日期。

SQL 一口十个松花蛋 发布于 2024-8-20 11:02 (编辑于 2024-8-20 13:30)
1min目标场景问卷 立即参与
回答问题
悬赏:3 F币 + 添加悬赏
提示:增加悬赏、完善问题、追问等操作,可使您的问题被置顶,并向所有关注者发送通知
共2回答
最佳回答
0
一口十个松花蛋Lv5见习互助
发布于2024-8-20 13:31

已解决,用了游标

最佳回答
1
JL98Lv6中级互助
发布于2024-8-20 13:33(编辑于 2024-8-20 13:34)

SQLSERVER 存储过程

CREATE PROCEDURE dbo.AllocatePaymentsToShipments

AS

BEGIN

    SET NOCOUNT ON;

    -- 假设存在两个表:Shipments 和 Payments

    -- Shipments 表有 ShipmentID, Amount, ShipmentDate

    -- Payments 表有 PaymentID, Amount, PaymentDate, SalesOrderID

    -- 临时表存储结果

    CREATE TABLE #Result (

        ShipmentID INT,

        AllocatedAmount DECIMAL(18, 2),

        AllocatedPaymentDate DATE

    );

    -- 变量用于跟踪当前处理的Payment和余额

    DECLARE @CurrentPaymentID INT, @CurrentPaymentAmount DECIMAL(18, 2), @RemainingPaymentAmount DECIMAL(18, 2), @CurrentPaymentDate DATE;

    -- 初始化变量

    SET @RemainingPaymentAmount = 0;

    -- 假设Payments已按PaymentDate排序,Shipments已按ShipmentDate排序

    -- 使用游标或循环遍历Payments和Shipments,这里使用CTE和窗口函数模拟

    -- 假设Payments已经根据SalesOrderID和PaymentDate排序

    WITH SortedPayments AS (

        SELECT 

            PaymentID, 

            Amount, 

            PaymentDate,

            ROW_NUMBER() OVER (PARTITION BY SalesOrderID ORDER BY PaymentDate) AS PaymentOrder

        FROM Payments

    ),

    SortedShipments AS (

        SELECT 

            ShipmentID, 

            Amount, 

            ShipmentDate,

            ROW_NUMBER() OVER (ORDER BY ShipmentDate) AS ShipmentOrder

        FROM Shipments

    ),

    Allocations AS (

        -- 这里需要一个复杂的逻辑来逐步分配付款,这里仅展示框架

        SELECT 

            sp.ShipmentID,

            sp.Amount,

            sp.ShipmentDate,

            CASE 

                -- 分摊逻辑,这里需要根据实际情况实现

                WHEN @RemainingPaymentAmount >= sp.Amount THEN sp.Amount

                WHEN @RemainingPaymentAmount > 0 THEN @RemainingPaymentAmount

                ELSE 0

            END AS AllocatedAmount,

            CASE 

                WHEN @RemainingPaymentAmount >= sp.Amount THEN @CurrentPaymentDate

                WHEN @RemainingPaymentAmount > 0 THEN @CurrentPaymentDate

                ELSE NULL

            END AS AllocatedPaymentDate,

            -- 更新剩余金额的逻辑

            @RemainingPaymentAmount = CASE 

                WHEN @RemainingPaymentAmount >= sp.Amount THEN @RemainingPaymentAmount - sp.Amount

                WHEN @RemainingPaymentAmount > 0 THEN 0

                ELSE @RemainingPaymentAmount

            END

        FROM SortedShipments sp

        CROSS APPLY (

            SELECT TOP 1 @CurrentPaymentID, @CurrentPaymentAmount, @CurrentPaymentDate

            FROM SortedPayments

            WHERE SalesOrderID = -- 假设有方式关联SalesOrderID到Shipment

                AND PaymentOrder = (

                    SELECT MAX(PaymentOrder)

                    FROM SortedPayments

                    WHERE SalesOrderID = -- 关联SalesOrderID

                        AND @RemainingPaymentAmount < Amount OR @RemainingPaymentAmount = 0

                )

            ORDER BY PaymentOrder

        ) ca

        -- 注意:这里的CROSS APPLY只是示意,实际实现会更复杂

    )

    -- 将分配结果插入到临时表

    INSERT INTO #Result (ShipmentID, AllocatedAmount, AllocatedPaymentDate)

    SELECT ShipmentID, AllocatedAmount, AllocatedPaymentDate

    FROM Allocations

    WHERE AllocatedAmount > 0;

    -- 后续处理,比如从临时表返回结果

    SELECT * FROM #Result;

    -- 清理临时表

    DROP TABLE #Result;

END

GO

  • 1关注人数
  • 194浏览人数
  • 最后回答于:2024-8-20 13:34
    请选择关闭问题的原因
    确定 取消
    返回顶部