Sql server 在SQL Server中,如何根据条件将所有月份动态分配给列?

Sql server 在SQL Server中,如何根据条件将所有月份动态分配给列?,sql-server,Sql Server,我有一个表,其中存储了产品名称、更新日期以及每月/每季度/每年的付款计划。现在,如果产品的付款计划是年度或月度,则会显示“获取续订月份”并显示当月的费率/金额,但如果付款计划是月度,则应在每个月之前显示费率/金额,如下所示 例如,如果一个名为ABC的产品的付款计划为每年,订阅率为276,续费日期为2019-12-01,而另一个产品XYZ的付款计划为每月,订阅率为17,续费日期为2019-08-15,那么我想要的结果集应该是这样的 ProductName RenewalMonth Rat

我有一个表,其中存储了产品名称、更新日期以及每月/每季度/每年的付款计划。现在,如果产品的付款计划是年度或月度,则会显示“获取续订月份”并显示当月的费率/金额,但如果付款计划是月度,则应在每个月之前显示费率/金额,如下所示

例如,如果一个名为ABC的产品的付款计划为每年,订阅率为276,续费日期为2019-12-01,而另一个产品XYZ的付款计划为每月,订阅率为17,续费日期为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
下面是我编写的查询,它返回数据库中存在的数据,但不是产品XYZ的12月份以外的月份。请记住,在付款计划为“每月”的情况下,这应仅显示所需日期中提供的所有其他月份的相同费率,对于其他付款计划,它应显示数据库中给定月份之前的费率

样本数据如下:

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]);
或通过以下方式获得第一条记录的年利率:

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条四次付款计划记录


为了得到您想要的结果,您应该将ItemDefinition表与PaymentPlanInterval连接起来。瞧。

您可以使用获得所有月份,并且根据您想要的输出,插入时必须是ABC-每月和XYZ作为每年@gotqn我正在创建一个报告,该报告也必须显示历史记录,因此,出于此目的,它应该从提供的日期开始。年度订阅不能转换为月份,因为它是年度订阅,客户希望在1年后付款,而不是每月付款。
create table PaymentPlanInterval(
    PaymentPlan VARCHAR(50),
    Interval varchar(50)
)