在我们的应用程序中,我们使用的是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
这个问题可能令人困惑。如果是的话,请告诉我。我会尽力给予正确的理解。
答案 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