我被要求创建一个存储过程来显示可变日期范围内的租赁项目数量。我有以下架构表:如何计算日期和时间因素的运行总数?
--Note that this is condensed, and in reality has proper constraints
--and more columns. Many dates from this table are tied to a single
--ContractDetail (separate table) by ContractDetailId.
CREATE TABLE RentalContractDates
(
RentalDateId INT IDENTITY(1,1) NOT NULL, --PK
ContractDetailId INT NOT NULL, --FK
RentalDate DATETIME NOT NULL,
Quantity DECIMAL(20,8) NULL
);
INSERT INTO RentalContractDates (ContractDetailId, RentalDate, Quantity)
VALUES (1, '04/01/2016 3:00 PM', 10),
(1, '04/10/2016 1:00 PM', 2),
(1, '04/15/2016 11:00 AM', -5),
(1, '04/15/2016 11:30 AM', -2),
(1, '04/27/2016 2:00 PM', -5);
用户将输入的日期范围进行搜索,并在过程应该找到属于此范围内的所有日期,然后在截止时间还因素,其中一个客户将在他们的租金另一天收取费用。
示例场景:全局截止时间设置为12:00 PM。我在2016年4月1日下午3点租用了10个小部件。这基本上意味着我实际上在4/02/2016租用了它们,因为它已经超过了04/01的截止时间。我在2016年4月10日下午1:00再租2个,基本上2016年4月11日。我于2016年4月15日上午11:00返回5个小工具,上午11:30还有2个小工具。我想在2016年4月27日归还所有小部件,但是我抵达中午12点的截止时间,因此,而不是4/02-4/27收取费用,实际上我将收取4/02 -4/28。
重要说明:如果我之前在04/01之前租用的数量是报告范围的开始,那么我需要将这些数据包括在报告中。例如,如果我在3月31日,4月1日有12次租赁,那么他们的总计就会增加12次。换句话说,任何以前的数量都需要计算在与输入的报告@BeginDate和@EndDate参数相加的总和中。 因此04/01会显示12,04/02会显示22等
正如您所看到的,我不需要用户每天输入他们的租金,我只是让他们设置开始日期和时间他们的租金与数量,并在他们下一次输入日期/时间组合,它将被重新总结。
当前代码:我想加入这个查询,查看整个月份的日历日期列表,并相应地设置它们的量。
DECLARE @BeginDate DATETIME = '04/01/2016',
@EndDate DATETIME = '04/28/2016';
DECLARE
@CutoffTime TIME = '12:00 PM';
SET @BeginDate = @BeginDate + @CutoffTime;
SET @EndDate = @EndDate + @CutoffTime;
SELECT gbd.ContractDetailId,
gbd.RentalDate,
gbd.Cutoff,
gbd.Quantity,
'Running Total' = SUM(Quantity) OVER (PARTITION BY ContractDetailId, RentalDate, Cutoff ORDER BY RentalDate)
FROM (
SELECT
r.ContractDetailId,
'RentalDate' = CONVERT(Date, RentalDate),
r2.Cutoff,
r.Quantity
FROM RentalContractDates r
INNER JOIN
(
SELECT
rcd.ContractDetailId,
'Cutoff' = CASE WHEN CONVERT(TIME, RentalDate) >= @CutoffTime THEN 'AFTER CUTOFF' ELSE 'BEFORE CUTOFF' END
FROM
RentalContractDates rcd
) r2
ON r2.ContractDetailId = r.ContractDetailId
WHERE
r.RentalDate Between @BeginDate and @EndDate
GROUP BY r.ContractDetailId, CONVERT(DATE, RentalDate), r2.Cutoff, Quantity
) gbd
ORDER BY RentalDate, Cutoff DESC
我想加入这个CTE的数据,并设置数量为每日期:
;WITH T([Date]) AS
(
SELECT @StartDate
UNION ALL
SELECT DATEADD(DAY,1,T.[Date]) FROM T WHERE T.[Date] < @EndDate
)
SELECT * FROM T
预期的最终输出: 完成后,报告将最终看起来像这样,尽管它将被转换并且包含星期几中的名称:
ContractDetailId RentalDate Quantity
----------------------------------------------------------------
1 04/01/2016 0 -- 0, because rentals were input after cutoff.
1 04/02/2016 10
1 04/03/2016 10 -- Continues until 4/10
1 04/10/2016 10
1 04/11/2016 12 -- Continues until 4/15
1 04/15/2016 5 -- I returned 5 and then 2, so this should sum since both were before the cutoff time.
-- Continues until 4/27.
1 04/27/2016 5 -- 5, because -5 was entered past cutoff on 4/27.
1 04/28/2016 0
我有沿着最终输出所需的动态SQL已经完成(如果需要,我可以发布这个动态SQL),但是我很遗憾如何通过截止前/截止后正确分组这些数据并相应地更改日期。我应该如何处理这种情况?感谢您的任何建议/帮助!
编辑1:修复不正确的采样数据。
您的示例数据似乎显示12个小工具出租和14个返回。虽然这可能是一个有利可图的商业模式,但它似乎有点关闭。 – HABO
要处理截止时间,只需从每个原始的'datetime'中减去'12 * 60 = 720'分钟,然后忽略时间部分:'CAST(DATEADD(minute,-720,RentalDate)AS date)'。 –
@HABO你说得对,不知道我是如何错过的。 04/15应该是5.我编辑它。 –