2016-03-04 2 views
3

я иметь следующую таблицуПользовательские расчет суммы

Date  Value promo item 
01/01/2011 626 0 1230 
01/02/2011 231 1 1230 
01/03/2011 572 1 1230 
01/04/2011 775 1 1230 
01/05/2011 660 1 1230 
01/06/2011 662 1 1230 
01/07/2011 541 1 1230 
01/08/2011 849 1 1230 
01/09/2011 632 1 1230 
01/10/2011 906 1 1230 
01/11/2011 961 1 1230 
01/12/2011 361 0 1230 
01/01/2012 461 0 1230 
01/02/2012 928 1 1230 
01/03/2012 855 0 1230 
01/04/2012 605 0 1230 
01/05/2012 83 0 1230 
01/06/2012 44 0 1230 
01/07/2012 382 0 1230 
01/08/2012 862 0 1230 
01/09/2012 549 0 1230 
01/10/2012 632 0 1230 
01/11/2012 2 0 1230 
01/12/2012 26 0 1230 

Я пытаюсь рассчитать среднюю сумму (SoldAmt)/число О.Д. дней между датой минимального и максимального момента Откат первые 28 строк (4 недели) в который promo = 1 по статье

Сглаживание составляет 4 недели на спине независимо от дневной скидки.

То есть, если такой товар находится в продвижении на неделю в течение последних 4 недель, сглаживание составляет более 5 недель без учета продвижения недели продаж.

Как рассчитать первые 4 недели/28 заказов на заказ по времени для promo = 1?

Стараюсь

  CREATE TABLE #RollingTotalsExample 
(
    [Date]  DATE 
    ,[Value] INT 
    ,promo float 
    ,item int 
); 

INSERT INTO #RollingTotalsExample 
SELECT '2011-01-01',626,1,1230 
UNION ALL SELECT '2011-02-01',231,1,1230 UNION ALL SELECT '2011-03-01',572,1,1230 
UNION ALL SELECT '2011-04-01',775,1,1230 UNION ALL SELECT '2011-05-01',660,1,1230 
UNION ALL SELECT '2011-06-01',662,1,1230 UNION ALL SELECT '2011-07-01',541,1,1230 
UNION ALL SELECT '2016-08-01',849,1,1230 UNION ALL SELECT '2016-09-01',632,1,1230 
UNION ALL SELECT '2016-10-01',906,1,1230 UNION ALL SELECT '2016-11-01',961,1,1230 
UNION ALL SELECT '2016-04-01',775,1,1230 UNION ALL SELECT '2016-05-01',660,1,1230 
UNION ALL SELECT '2016-06-01',662,1,1230 UNION ALL SELECT '2016-07-01',541,1,1230 
UNION ALL SELECT '2016-08-01',849,1,1230 UNION ALL SELECT '2016-09-01',632,1,1230 
UNION ALL SELECT '2016-10-01',906,1,1230 UNION ALL SELECT '2016-11-01',961,1,1230 
UNION ALL SELECT '2016-12-01',361,0,1230 UNION ALL SELECT '2012-01-01',461,0,1230 
UNION ALL SELECT '2012-02-01',928,0,1230 UNION ALL SELECT '2012-03-01',855,0,1230 
UNION ALL SELECT '2012-04-01',605,0,1230 UNION ALL SELECT '2012-05-01',83,0,1230 
UNION ALL SELECT '2012-06-01',44,0,1230 UNION ALL SELECT '2012-07-01',382,0,1230 
UNION ALL SELECT '2012-08-01',862,0,1230 UNION ALL SELECT '2012-09-01',549,0,1230 
UNION ALL SELECT '2012-10-01',632,0,1230 UNION ALL SELECT '2012-11-01',2,0,1230 
UNION ALL SELECT '2012-12-01',26,0,1230; 
SELECT * FROM #RollingTotalsExample; 

    -- Rolling twelve month total by using INNER JOIN 
    SELECT a.[Date] 
     ,Value=MAX(CASE WHEN a.[Date] = b.[Date] THEN a.Value END) 
     ,Rolling12Months=CASE 
          WHEN ROW_NUMBER() OVER (ORDER BY a.[Date]) < 12 
          THEN NULL 
          ELSE SUM(b.Value) 
          END 
    FROM #RollingTotalsExample a 
    JOIN #RollingTotalsExample b ON b.[Date] BETWEEN DATEADD(month, -11, a.[Date]) AND a.[Date] 
    GROUP BY a.[Date] 
    ORDER BY a.[Date]; 

Теперь, как изменить запрос, чтобы вычислить среднюю сумму (SoldAmt)/число О.Д. дней между датой мин и макс даты откате порядок данных 28 первых строк по времени промо = 1 статьи

+3

Это хороший вопрос (upvote с моей стороны), особенно из-за к скопированному тестовому коду ** с образцами данных **. Остается только одно: ожидаемый результат, соответствующий данным. Не могли бы вы добавить это на свой вопрос? – Shnugo

+0

Что означает откат первых 12 дней, означает ли это, что вы не хотите, чтобы первый 12-дневный порядок данных по времени для promo = 1? – TheGameiswar

+0

@ TheGameiswar да точно. –

ответ

1

Вот альтернативный подход, требующий LAG(), который доступен на SQL 2012, но обратите внимание, что данные примера не содержат «28 отдельных дней» до каждой даты. Также используемый фактический тип данных неизвестен (дата/smalldatetime/datetime/datetime2), и не известно, требуется ли время усечения с даты. Таким образом, с некоторыми оговорками, этот подход создает серию диапазонов дат для 28 разных дат (но данные не предоставляют их, тогда это 28 прошедших дней). Вот это sqlfiddle demo

PostgreSQL 9.3 Схема установки: (как SQL Server не работает на sqlfiddle)

CREATE TABLE Table1 
    (theDate timestamp, Value int, promo int, item int) 
; 

INSERT INTO Table1 
    (theDate, Value, promo, item) 
VALUES 
    ('2011-01-01 00:00:00', 626, 0, 1230), 
    ('2011-01-02 00:00:00', 231, 1, 1230), 
    ('2011-01-03 00:00:00', 572, 1, 1230), 
    ('2011-01-04 00:00:00', 775, 1, 1230), 
    ('2011-01-05 00:00:00', 660, 1, 1230), 
    ('2011-01-06 00:00:00', 662, 1, 1230), 
    ('2011-01-07 00:00:00', 541, 1, 1230), 
    ('2011-01-08 00:00:00', 849, 1, 1230), 
    ('2011-01-09 00:00:00', 632, 1, 1230), 
    ('2011-01-10 00:00:00', 906, 1, 1230), 
    ('2011-01-11 00:00:00', 961, 1, 1230), 
    ('2011-01-12 00:00:00', 361, 0, 1230), 
    ('2012-01-01 00:00:00', 461, 0, 1230), 
    ('2012-01-02 00:00:00', 928, 1, 1230), 
    ('2012-01-03 00:00:00', 855, 0, 1230), 
    ('2012-01-04 00:00:00', 605, 0, 1230), 
    ('2012-01-05 00:00:00', 83, 0, 1230), 
    ('2012-01-06 00:00:00', 44, 0, 1230), 
    ('2012-01-07 00:00:00', 382, 0, 1230), 
    ('2012-01-08 00:00:00', 862, 0, 1230), 
    ('2012-01-09 00:00:00', 549, 0, 1230), 
    ('2012-01-10 00:00:00', 632, 0, 1230), 
    ('2012-01-11 00:00:00', 2, 0, 1230), 
    ('2012-01-12 00:00:00', 26, 0, 1230) 
; 

Query 1:

select 
     t1.item 
    , ranges.theStart 
    , ranges.theEnd 
    , sum(t1.value) 
    , sum(t1.value)/28 avg 
from (
     select 
      coalesce(lag(theDay,28) over(order by theDay) , theDay - INTERVAL '28 DAYS') as theStart 
      , theDay as theEnd 
     from (
      select distinct cast(thedate as date) theDay from Table1 
      ) days 
    ) ranges 
inner join table1 t1 on theDate between ranges.theStart and ranges.theEnd 
group by 
     t1.item 
    , ranges.theStart 
    , ranges.theEnd 

Results:

| item |     thestart |     theend | sum | avg | 
|------|----------------------------|---------------------------|------|-----| 
| 1230 | December, 04 2010 00:00:00 | January, 01 2011 00:00:00 | 626 | 22 | 
| 1230 | December, 05 2010 00:00:00 | January, 02 2011 00:00:00 | 857 | 30 | 
| 1230 | December, 06 2010 00:00:00 | January, 03 2011 00:00:00 | 1429 | 51 | 
| 1230 | December, 07 2010 00:00:00 | January, 04 2011 00:00:00 | 2204 | 78 | 
| 1230 | December, 08 2010 00:00:00 | January, 05 2011 00:00:00 | 2864 | 102 | 
| 1230 | December, 09 2010 00:00:00 | January, 06 2011 00:00:00 | 3526 | 125 | 
| 1230 | December, 10 2010 00:00:00 | January, 07 2011 00:00:00 | 4067 | 145 | 
| 1230 | December, 11 2010 00:00:00 | January, 08 2011 00:00:00 | 4916 | 175 | 
| 1230 | December, 12 2010 00:00:00 | January, 09 2011 00:00:00 | 5548 | 198 | 
| 1230 | December, 13 2010 00:00:00 | January, 10 2011 00:00:00 | 6454 | 230 | 
| 1230 | December, 14 2010 00:00:00 | January, 11 2011 00:00:00 | 7415 | 264 | 
| 1230 | December, 15 2010 00:00:00 | January, 12 2011 00:00:00 | 7776 | 277 | 
| 1230 | December, 04 2011 00:00:00 | January, 01 2012 00:00:00 | 461 | 16 | 
| 1230 | December, 05 2011 00:00:00 | January, 02 2012 00:00:00 | 1389 | 49 | 
| 1230 | December, 06 2011 00:00:00 | January, 03 2012 00:00:00 | 2244 | 80 | 
| 1230 | December, 07 2011 00:00:00 | January, 04 2012 00:00:00 | 2849 | 101 | 
| 1230 | December, 08 2011 00:00:00 | January, 05 2012 00:00:00 | 2932 | 104 | 
| 1230 | December, 09 2011 00:00:00 | January, 06 2012 00:00:00 | 2976 | 106 | 
| 1230 | December, 10 2011 00:00:00 | January, 07 2012 00:00:00 | 3358 | 119 | 
| 1230 | December, 11 2011 00:00:00 | January, 08 2012 00:00:00 | 4220 | 150 | 
| 1230 | December, 12 2011 00:00:00 | January, 09 2012 00:00:00 | 4769 | 170 | 
| 1230 | December, 13 2011 00:00:00 | January, 10 2012 00:00:00 | 5401 | 192 | 
| 1230 | December, 14 2011 00:00:00 | January, 11 2012 00:00:00 | 5403 | 192 | 
| 1230 | December, 15 2011 00:00:00 | January, 12 2012 00:00:00 | 5429 | 193 | 

NB: Для SQL Server

  • вместо theDay - INTERVAL '28 DAYS' использования DateAdd (день -28, theDay)
0

, если вы ищете кумулятивную сумму за все дни, за исключением первых 12 дней с MinDate ...

with cte 
as 
(
select dateadd(day,12,min(date)) as mindate,max(date) as maxdate, 
datediff(day,dateadd(day,12,min(date)),max(date)) as n 

from #RollingTotalsExample 
) 
select 
date, 
(select sum(value) from #RollingTotalsExample t2 where t2.date<=t1.date) as rollingsum, 
promo, 
item, 
mindate, 
maxdate 
from 
#RollingTotalsExample t1 
join 
cte c 
on t1.date >=c.mindate and t1.date<= c.maxdate 
order by date 

--this соответствует вашему точному выходу

with cte 
as 
(
select dateadd(day,12,min(date)) as mindate,max(date) as maxdate, 
datediff(day,dateadd(day,12,min(date)),max(date)) as n 

from #RollingTotalsExample 
) 
select 
date, 
sum(value) as avgsum, 
promo, 
item 
from 
#RollingTotalsExample t1 
join 
cte c 
on t1.date >=c.mindate and t1.date<= c.maxdate 
where promo=1 
group by date,promo,item 
order by date 

--- если вы ищете средн: сумма/нет дней

with cte 
as 
(
select dateadd(day,12,min(date)) as mindate,max(date) as maxdate, 
datediff(day,dateadd(day,12,min(date)),max(date)) as n 

from #RollingTotalsExample 
) 
select 
date, 
sum(value)/n*1.0 as avgsum, 
promo, 
item 
from 
#RollingTotalsExample t1 
join 
cte c 
on t1.date >=c.mindate and t1.date<= c.maxdate 
where promo=1 
group by date,promo,item,n 
order by date 
+0

Как я могу получить первые 12 строк данных по времени для promo = 1? –

+0

Всего суммарная сумма или avg – TheGameiswar

+0

Я ищу, чтобы получить данные из первых 12 рядов (ромбетов) по времени для promo = 1 по статьям –

1

Потому что не указано/показали «ожидаемый результат» Я предполагаю, что совсем немного. Хотя я прочитал слова этого вопроса и the duplicate, я действительно не понимаю описания. С этими оговорками я предлагаю следующее:

Результат:

| item | promo_start | max_date | sum | count | avg | 
|------|-------------|-------------|------|-------|-----| 
| 1230 | Jan 02 2011 | Jan 12 2011 | 7150 | 11 | 650 | 
| 1230 | Jan 02 2012 | Jan 12 2012 | 4968 | 11 | 451 | 

Произведенный следующего запроса (с использованием Postgres):

select 
     item 
    , promo_start 
    , max(thedate) max_date 
    , sum(value) 
    , count(distinct thedate) 
    , sum(value)/count(distinct thedate) avg 
from (
     select * 
     from table1 t1 
     cross join lateral (
      select min(t2.thedate) promo_start 
      from table1 t2 
      where promo = 1 
      and t1.item = t2.item 
      and t2.thedate <= t1.thedate 
      and t2.thedate >= t1.thedate - INTERVAL '28 DAYS' 
      ) a 
    ) d 
where promo_start is NOT NULL 
group by 
     item 
    , promo_start 
; 

Смотрите это как a demo at sqlfiddle (NB: SQL-сервер является/есть не работает на этом участке в течение нескольких недель, поэтому Postgres использовали вместо него)

NB: для SQL Server

  1. вместо `перекрестного соединения бокового» использовать CROSS APPLY
  2. вместо t1.thedate - INTERVAL '28 DAYS' использование DATEADD (день, -28, t1.thedate)

Логика заключается в следующем:

  1. перекрестное соединение боковой (крест применить) подзапрос находит минимальную дату, в которой элемент был на продвижение в предшествующем уровне 28 дни
  2. , что минимальная дата повторяется на каждую строке в течение периода акции пострадало
  3. только те строк, которые пострадали от продвижения затем выбранного
  4. , то позиция и дата начала акции используются для группировки выбранных строк, с агрегатами, используемыми для расчета среднего значения
  5. Число отдельных дней используется для расчета среднего значения, так как продажи не могут возникать в каждый день в течение 28-дневного периода ,

+ Я использовал «theDate» в качестве имени столбца просто потому, что «дата» слишком запутанна как в коде, так и в описании кода. Я действительно не могу рекомендовать использовать «дату» в качестве имени столбца.

+0

Я рассчитываю рассчитать среднее значение суммы для первых отчетных 28 предыдущих дат не в течение 28-дневного периода, когда promo = 1 для каждого элемента. Это расчет для первых отличных 28 предыдущих дат, существующих в таблице, в которой promo = 1 по позиции. –

+0

Являются ли данные о дате/времени хранимыми ВСЕМИ раз в 00:00:00? (т. е. только даты)? –

+0

Под данными в вопросе вы указываете: * Я пытаюсь вычислить среднюю сумму (SoldAmt)/число od days между датой min и максимальной датой, откатывающей первые 28 строк (4 недели) * **, в которых promo = 1 на Статья ** - так что вы можете видеть, как разочарование пытается объяснить ваши потребности только словами, в этом заявлении вы заявили, что вам нужен promo = 1; но в первом комментарии по моему предложению вы заявляете, что это не нужно. –

Смежные вопросы