Как динамически распределить все месяцы на основе столбца при условии в SQL Server? - PullRequest
5 голосов
/ 07 ноября 2019

У меня есть таблица, в которой я храню 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)

imageOffice 365 Essential' has Monthly subscription as per my record so it has to be displayed under each month.">

Ответы [ 2 ]

2 голосов
/ 07 ноября 2019

Это может выглядеть примерно так:

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]);
0 голосов
/ 07 ноября 2019

Мой совет - ввести дополнительную таблицу, в которой будет одна запись для годового плана и 12 записей для месячного плана. Например:

create table PaymentPlanInterval(
    PaymentPlan VARCHAR(50),
    Interval varchar(50)
)

И, возможно, эта таблица может содержать 2 записи для полугодового плана платежей и 4 записи для квартального плана.

Чтобы получить желаемый результат, вы должны присоединитьсяВаша таблица ItemDefinition с помощью PaymentPlanInterval. Вуаля.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...