[英]How to dynamically allocate all months based to a column on condition in SQL Server?
我有一张表格,其中存储了Product Name
和Renewal Date
以及付款计划(Monthly/Quarterly/Yearly)
。 现在,如果产品的付款计划是Yearly or Monthly
,它将显示获取续订月份并显示该月的Rate/Amount
,但如果付款计划是Monthly
,它应该在每个月的前面显示Rate/Amount
如下图所示。
例如,如果一个名为ABC
的产品的付款计划为Yearly
,订阅率为276
, Renewal Date
2019-12-01
,而另一个产品XYZ
的付款计划为Monthly
,订阅率为17
, Renewal Date
2019-08-15
,那么我想要的结果集应该是这样的
ProductName RenewalMonth Rate
------------------------------------
ABC December 276
XYZ January 17
XYZ February 17
XYZ March 17
XYZ April 17
XYZ May 17
XYZ June 17
XYZ July 17
XYZ August 17
XYZ September 17
XYZ October 17
XYZ November 17
XYZ December 17
这是我编写的查询,它返回数据库中存在的数据,但不是十二月以外的月份Product XYZ
。 请记住,这应该只显示在付款计划为'Monthly'
的所需日期中提供的所有其他月份的相同费率,对于其他付款计划,它应该在数据库中显示的给定月份前面显示费率。
样本数据如下:
CREATE TABLE ItemDefinition
(
ID INT NOT NULL,
ProductName VARCHAR(50),
PaymentPlan VARCHAR(50),
RenewalDate DATETIME,
UnitRate NUMERIC(18, 0)
);
INSERT INTO ItemDefinition
VALUES (1, 'ABC', 'Yearly', '2019-12-01', 276),
(1, 'XYZ', 'Monthly', '2019-08-15', 17);
我正在写的查询是
SELECT
ProductName, SUM(UnitRate) Rate,
DATENAME(MONTH , DATEADD(MONTH , MONTH(RenewalDate)-1 , '1900-01-01')) RenewalMonth
FROM
ItemDefinition
WHERE
MONTH(RenewalDate) IS NOT NULL
AND RenewalDate BETWEEN @dtStart AND @dtEnd
GROUP BY
ProductName, MONTH(RenewalDate)
ORDER BY
MONTH(RenewalDate)
它可能是这样的:
DECLARE @DateBeg DATE = '2019-01-01'
,@DateEnd DAte = '2020-12-01';
WITH Ranges AS
(
SELECT *
,@DateBeg AS [DateBeg]
,@DateEnd AS [DateEnd]
FROM ItemDefinition DS
)
SELECT *
,DATENAME(MONTH ,ISNULL([GeneratedDate], [RenewalDate])) AS RenewalMonth
FROM Ranges
OUTER APPLY
(
SELECT DATEADD(MONTH, [number], [DateBeg])
FROM
(
select number
from master.dbo.spt_values
where [type] = 'P'
) numbers
WHERE DATEADD(MONTH, [number], [DateBeg]) < [DateEnd]
AND [PaymentPlan] = 'Monthly'
) AutoDates ([GeneratedDate]);
您可以将DateEnd
参数更改为更少,您将看到生成的月份数减少了多少。
这个想法是为每一行设置start
和end
日期,并根据它来生成你的月份。
要获取这些年的记录,请使用以下命令:
WITH Ranges AS
(
SELECT *
,@DateBeg AS [DateBeg]
,@DateEnd AS [DateEnd]
FROM ItemDefinition DS
)
SELECT *
,DATENAME(MONTH ,ISNULL([GeneratedDate], [RenewalDate])) AS RenewalMonth
,IIF([PaymentPlan] = 'Monthly', [UnitRate], IIF(CONVERT(VARCHAR(7), [RenewalDate], 121) = CONVERT(VARCHAR(7), [GeneratedDate], 121), [UnitRate], NULL))
FROM Ranges
OUTER APPLY
(
SELECT DATEADD(MONTH, [number], [DateBeg])
FROM
(
select number
from master.dbo.spt_values
where [type] = 'P'
) numbers
WHERE DATEADD(MONTH, [number], [DateBeg]) < [DateEnd]
) AutoDates ([GeneratedDate]);
或以下获取第一条记录的年率:
DECLARE @DateBeg DATE = '2019-01-01'
,@DateEnd DAte = '2020-12-01';
WITH Ranges AS
(
SELECT *
,@DateBeg AS [DateBeg]
,@DateEnd AS [DateEnd]
FROM ItemDefinition DS
)
SELECT *
,DATENAME(MONTH ,ISNULL([GeneratedDate], [RenewalDate])) AS RenewalMonth
,IIF([PaymentPlan] = 'Monthly', [UnitRate], IIF([number] = 0, [UnitRate], NULL))
FROM Ranges
OUTER APPLY
(
SELECT DATEADD(MONTH, [number], [DateBeg])
,[number]
FROM
(
select number
from master.dbo.spt_values
where [type] = 'P'
) numbers
WHERE DATEADD(MONTH, [number], [DateBeg]) < [DateEnd]
) AutoDates ([GeneratedDate], [number]);
我的建议是引入一个附加表,该表将有一条记录用于年度计划和 12 条记录用于月度计划。 例如:
create table PaymentPlanInterval(
PaymentPlan VARCHAR(50),
Interval varchar(50)
)
也许这个表可能包含 2 条半年支付计划的记录和 4 条季度计划的记录。
为了获得您想要的结果,您应该使用 PaymentPlanInterval 加入您的 ItemDefinition 表。 瞧。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.