在SQL中,在多行之间拆分金额

时间:2014-11-21 15:20:38

标签: sql sql-server

在我们的应用程序中,我们使用的是SQL Server 2012.我遇到了一种情况,我无法想出一个可以解决我的目的的单个查询(没有循环)。让我解释一下。

我有旅行表 -

ID       State      Days_Count   Remaining_Days
1         AL          20            -
2         AL          2             -
3         AL          14            -

我有另一张 Travel_Sum

的表格
State      Days_Sum   Max_Limit    Exceeding_Amt
AL           36          12             24

其他国家/地区有更多条目。我正在尝试编写的单个查询将使用 Exceeding_Amt 更新剩余天数。在此示例中,Exceeding_Amt列的值为24.因此,在第一个表中,我尝试更新值20(days_Count的最大值)对剩余天数,2对第二行和(24-20-2)2对最后一行。

基本上我必须在状态匹配的第一个表的行中分割超过量(即24)。因此,为了拆分24,我想将第一行的remaining_days更新为20.因为我无法使用超过days_count的值进行更新。所以我还剩4天了。 对于第二行,Days_count为2.所以我用2更新了这一行(我允许输入的最大值)。在第三行中,我更新了剩余2天的Remaining_Days列值。

期望的输出:

ID       State      Days_Count   Remaining_Days
1         AL          20            20
2         AL          2             2
3         AL          14            2

这个问题可能令人困惑。如果是的话,请告诉我。我会尽力给予正确的理解。

2 个答案:

答案 0 :(得分:3)

以下内容对您有用:

UPDATE  t
SET     Remaining_Days = CASE WHEN CumulativeDayCount < Exceeding_Amt THEN Days_Count
                                WHEN (CumulativeDayCount - Days_Count) > Exceeding_Amt THEN 0
                                ELSE Exceeding_Amt - (CumulativeDayCount - Days_Count)
                            END
FROM    (   SELECT  t.ID,
                    t.Days_Count,
                    t.[State],
                    CumulativeDayCount = SUM(t.Days_Count) OVER(PARTITION BY t.[State] ORDER BY t.ID),
                    t.Remaining_Days,
                    ts.Exceeding_Amt
            FROM    Travel AS t
                    INNER JOIN Travel_Sum AS ts
                        ON ts.[State] = t.[State]
        ) AS t;

这里的主要步骤是使用窗口函数SUM() OVER()获取累积天数:

SELECT  t.ID,
        t.Days_Count,
        CumulativeDayCount = SUM(t.Days_Count) OVER(PARTITION BY t.[State] ORDER BY t.ID)
FROM    Travel AS t;

这给出了:

ID  Days_Count  State   CumulativeDayCount
1   20          AL      20
2   2           AL      22
3   14          AL      36

然后,您可以加入您的总和表,获取Exceeding_Amt列,并根据累计总数确定是否应该应用所有,部分或全部。这是案例表达的来源:

CASE WHEN CumulativeDayCount < Exceeding_Amt THEN Days_Count
    WHEN (CumulativeDayCount - Days_Count) > Exceeding_Amt THEN 0
    ELSE Exceeding_Amt - (CumulativeDayCount - Days_Count)
END

如果您只需要一个选择语句,并且实际上不需要更新您的表格,您可以使用:

SELECT  t.ID,
        t.State,
        t.Days_Count,
        Remaining_Days = CASE WHEN CumulativeDayCount < Exceeding_Amt THEN Days_Count
                                WHEN (CumulativeDayCount - Days_Count) > Exceeding_Amt THEN 0
                                ELSE Exceeding_Amt - (CumulativeDayCount - Days_Count)
                            END
FROM    (   SELECT  t.ID,
                    t.Days_Count,
                    t.[State],
                    CumulativeDayCount = SUM(t.Days_Count) OVER(PARTITION BY t.[State] ORDER BY t.ID),
                    ts.Exceeding_Amt
            FROM    Travel AS t
                    INNER JOIN Travel_Sum AS ts
                        ON ts.[State] = t.[State]
        ) AS t;

<强> Example on SQL Fiddle

答案 1 :(得分:0)

以下使用CTE方法运行计算总计。

DECLARE @Travel TABLE (ID INT, State VARCHAR(10), Days_Count INT)
DECLARE @Travel_Sum TABLE (State VARCHAR(10), Exceeding_Amt INT)

INSERT @Travel VALUES (1, 'AL', 20), (2, 'AL', 2), (3, 'AL', 14)
INSERT @Travel_Sum VALUES ('AL', 24)

;WITH TravelRows AS (
    SELECT
        ID,
        State,
        Days_Count,
        ROW_NUMBER() OVER (PARTITION BY State ORDER BY ID) AS RowNum
    FROM @Travel
), CTE AS (
    SELECT
        TR.ID,
        TR.State,
        TR.Days_Count,
        TR.RowNum,
        TS.Exceeding_Amt - TR.Days_Count AS Exceeding_Amt,
        CASE WHEN TS.Exceeding_Amt > TR.Days_Count THEN TR.Days_Count ELSE TS.Exceeding_Amt END AS Remaining_days
    FROM TravelRows TR
        INNER JOIN @Travel_Sum TS 
            ON TR.State = TS.State
    WHERE RowNum = 1
    UNION ALL
    SELECT
        R2.ID,
        R2.State,
        R2.Days_Count,
        R2.RowNum,
        R1.Exceeding_Amt - R2.Days_Count,
        CASE WHEN R1.Exceeding_Amt > R2.Days_Count THEN R2.Days_Count ELSE R1.Exceeding_Amt END AS Remaining_days
    FROM CTE R1
        INNER JOIN TravelRows R2
            ON R1.State = R2.State
                AND R1.RowNum + 1 = R2.RowNum
)
    SELECT
        ID,
        State,
        Days_Count,
        Remaining_Days
    FROM CTE
    OPTION (MAXRECURSION 0)

输出:

ID          State      Days_Count  Remaining_Days
----------- ---------- ----------- --------------
1           AL         20          20
2           AL         2           2
3           AL         14          2
相关问题