Как получить сумму за последний х год - PullRequest
0 голосов
/ 03 октября 2019

У нас есть таблица Test с CoID, PeriodType (M для месяца, Q для квартала), FinDate (дата конца месяца) и Sales, как показано ниже:

CREATE TABLE Test(
   [CoID] [int] NOT NULL,
   [PeriodType] [varchar](50) NOT NULL,
   [FinDate] [datetime] NOT NULL,
   [Sales] [float] NOT NULL
) 

Нам нужно получить продажи дляпоследний х год. Если в таблице нет повторяющихся данных (если есть данные за 31.10.18 с PeriodType = "M", не будет данных за 31.12.19 с PeriodType = "Q"), я могу использоватьПриведенный ниже запрос для получения продаж за последний 1 год

SELECT SUM(SALES) FROM TEST WHERE FINDATE >= EOMONTH(getdate(),-12) GROUP BY COID

Если в таблице есть повторяющиеся данные (есть данные за 31.10.18 с PeriodType = "M", но есть и данныедля 31.12.19 с PeriodType = "Q", как должен выглядеть запрос?

Кроме того, если нет данных за 1 месяц за последний год, я хочу вернуть 0, например, дляполучить данные о продажах за последний 1 год, но нет данных за 30.11.18, затем я хочу вернуть 0. Как будет выглядеть запрос?

CoID   PeriodType    FinDate              Sales
1             M      9/30/18              11
1             M      10/31/18             10
1             M      11/30/18             10
1             M      12/31/18             10
1             Q      3/31/19              10
1             Q      6/30/19              10
1             M      7/31/19              10
1             M      8/31/19              10
1             M      9/30/19              10

2             M      10/31/18             11
2             M      11/30/18             12
2             M      12/31/18             13
2             Q      3/31/19              14
2             M      4/30/19              15
2             M      5/31/19              16
2             M      6/30/19              17

Желаемые результаты

CoID    SumSales
1       80   --> doesn't include sales from 9/30/18 (1 year ago starts from 10/31/18)
2       0    --> missing sales from 7/31/19, 8/31/19 and 9/30/19, so we set sales to 0

Ответы [ 2 ]

0 голосов
/ 03 октября 2019

Похоже, что это работает с примерами данных.

встроенные комментарии.

declare @table table (CoID int, PeriodType varchar(1), FinDate date, Sales int)

insert into @table
values (1, 'M'      ,'9/30/18' ,11),
(1, 'M'      ,'10/31/18',10),
(1, 'M'      ,'11/30/18',10),
(1, 'M'      ,'12/31/18',10),
(1, 'Q'      ,'3/31/19' ,10),
(1, 'Q'      ,'6/30/19' ,10),
(1, 'M'      ,'7/31/19' ,10),
(1, 'M'      ,'8/31/19' ,10),
(1, 'M'      ,'9/30/19' ,10),
(2, 'M'      ,'10/31/18',11),
(2, 'M'      ,'11/30/18'             ,12),
(2, 'M'      ,'12/31/18'             ,13),
(2, 'Q'      ,'3/31/19'              ,14),
(2, 'M'      ,'4/30/19'              ,15),
(2, 'M'      ,'5/31/19'              ,16),
(2, 'M'      ,'6/30/19'              ,17)

-- We need a table of months so we can determine if anything is missing.
declare @months table (mnth int)
insert into @months
values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)


-- This CTE takes the Quarter's sales and turns them into 3 months' sales
;with CTEquarterToMonth as (
-- start with the last month of a quarter
select CoID, month(FinDate) mnth, Sales
from @table t3
where findate >= eomonth(getdate(),-12)
    and periodtype = 'Q'

union all

-- this is the 2nd month of the quarter, but only if it is also within 1 year
select CoID, month(dateadd("m",-1,FinDate)) mnth, 0 Sales
from @table t3
where findate >= eomonth(getdate(),-11)
    and periodtype = 'Q'

union all

-- this is the 1st month of the quarter, but only if it is also within 1 year
select CoID, month(dateadd("m",-2,FinDate)) mnth, 0 Sales
from @table t3
where findate >= eomonth(getdate(),-10)
    and periodtype = 'Q'

),

-- This CTE adds individual months to the months we already have gotten
-- from the Quarters' sales.
CTEcombinedMonths as (
    select *
    from CTEquarterToMonth

    union all

    select CoID, month(FinDate) mnth, Sales
    from @table t
    where findate >= eomonth(getdate(),-12)
        and periodtype = 'M'
        and not exists (select 1 -- This ignores duplicate months
                        from CTEquarterToMonth cte
                        where cte.CoID = t.CoID
                            and cte.mnth = month(FinDate)
                        )
)


select months.CoID,
    -- The following case statement will set the sales to 0
    -- if there are any missing months for a given CoID.
    case when sum(case when cte.mnth is null then 1 else 0 end) > 0
         then 0
         else sum(Sales)
    end YearSales
from (  -- derive a table of CoID's and all 12 months
    select CoID, mnth
    from @months 
     inner join (
        select distinct CoID
        from @table
    ) t on 1=1
) months
-- left join so we can find the missing months
left outer join CTEcombinedMonths cte
    on months.CoID = cte.CoID
    and months.mnth = cte.mnth
group by months.CoID

Вдохновленный частью ответа Мишель, мне нравится использовать count вместо таблицы @months. Вы можете полностью избавиться от таблицы @months и использовать следующий запрос после всех объявлений CTE:

select CoID,
    -- The following case statement will set the sales to 0
    -- if there are any missing months for a given CoID.
    case when count(*) <> 12
         then 0
         else sum(Sales)
    end YearSales
from CTEcombinedMonths cte
group by CoID
0 голосов
/ 03 октября 2019
--in case you want results from several years, you can create your own calendar.
--If not, you can replace the dates of the 'between' statement in the next query
select   EOMONTH(getdate(),-13) as first_day_of_your_year
       , EOMONTH(EOMONTH(getdate(),-13), +12) as last_day_of_your_year
       , '1' as your_year 
into your_years_table;


--add your year to the table
select  a.*, b.your_year
into    Test2
from    Test a join  your_years_table b
on (a.FinDate between b.first_day_of_your_year and b.last_day_of_your_year);
-- here I strongly assume that the entire quarter belongs to a single year (the year of the last day of the quarter).


--group by CoID and year 
select    CoID
        , your_year
        , sum(case when PeriodType = 'M' then 1 else 3 end) as count_months
        , Sum(Sales) as total_sales
into Test3
from Test2
where your_year is not null
group by CoID, your_year;


--if there is no data for 1 month in the last year, you get 0
select    CoID
        , your_year
        , case when count_months = 12 then total_sales else 0 end as sum_sales
into Test4
from Test3
where your_year = '1';
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...