Промежуточный итог за диапазон дат - заполните пропущенные даты - PullRequest
2 голосов
/ 21 февраля 2012

У меня есть следующая таблица.

DATE  | AMT
10/10 | 300
12/10 | 300
01/11 | 200
03/11 | 100

Как получить месячную сумму? Результат как -

DATE | TOT
1010 | 300
1110 | 300
1210 | 600 
0111 | 800
0211 | 800
0311 | 900

SQL-заявление типа

SELECT SUM(AMT) FROM TABLE1 WHERE DATE BETWEEN '1010' AND '0111'

приведет к 800 для 0111, но ...

ПРИМЕЧАНИЕ Ограничения по дате отсутствуют. это моя дилемма Как заполнить этот столбец, не выполняя цикл для всех дат, а также отображать пропущенные месяцы?

Ответы [ 4 ]

2 голосов
/ 21 февраля 2012

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

Думайте об этом как о кешировании. Вместо того, чтобы перебирать и заполнять пробелы, просто поместите календарь в вашу базу данных.

Вы даже можете объединить несколько календарей (начало месяца, начало недели, праздничные дни, рабочий день и т. Д.) В одну таблицу с кучей поисковых флагов и индексов.

В итоге получается что-то вроде ...

SELECT
  calendar.date,
  SUM(data.amt)
FROM
  calendar
LEFT JOIN
  data
    ON  data.date >= calendar.date
    AND data.date <  calendar.date + INTERVAL 1 MONTH
WHERE
      calendar.date >= '20110101'
  AND calendar.date <  '20120101'
GROUP BY
  calendar.date

EDIT

Я только что заметил, что ОП хочет получить промежуточный итог.

Это возможно в SQL, но крайне неэффективно. Причина в том, что результат одного месяца не используется для вычисления следующего месяца. Вместо этого весь промежуточный итог должен быть снова рассчитан.

По этой причине, как правило, настоятельно рекомендуется рассчитать месячную сумму, как указано выше, а затем использовать свое приложение для ее прохождения и получения значений промежуточных итогов.

Если вы действительно должны сделать это в SQL, это будет что-то вроде ...

SELECT
  calendar.date,
  SUM(data.amt)
FROM
  calendar
LEFT JOIN
  data
    ON  data.date >= @yourFirstDate
    AND data.date <  calendar.date + INTERVAL 1 MONTH
WHERE
      calendar.date >= @yourFirstDate
  AND calendar.date <  @yourLastDate
GROUP BY
  calendar.date
0 голосов
/ 21 февраля 2012

Вы также можете сгенерировать диапазон на лету, передать его значение как интервал в DATE_ADD и, в основном, проецировать последовательность значений месяца.

Как сказал @Dems, вам нужно иметь коррелированный подзапрос для вычисления промежуточного итога, который будет очень неэффективным, потому что он будет запускать вложенный цикл внутри.

Чтобы увидеть, как создать последовательность, проверьте мой пост здесь: Как сгенерировать диапазон чисел в Mysql

Конечный запрос должен выглядеть примерно так: (кстати, у вас должен быть столбец даты, а не этот беспорядок varchar).

/*NOTE: This assumes a derived table (inline view) containing the sequence of date values and their corresponding TOT value*/
SELECT
  DATEVALUES.DateValue,
  (
  SELECT SUM(TABLE1.AMT) FROM TABLE1 WHERE TABLE1.DateValue <= DATEVALUES.DateValue)
  ) AS RunningSubTotal
FROM
  DATEVALUES

Или что-то в этом роде.

0 голосов
/ 21 февраля 2012

основная проблема - and have the missing months displayed as well? Я не вижу, как это сделать без таблицы aux, содержащей отображаемую комбинацию месяц \ год:

create table table1(
date datetime,
amt int
)
insert into table1 values ('10/10/2010',100)
insert into table1 values ('12/12/2010',200)
insert into table1 values ('01/01/2011',50)
insert into table1 values ('03/03/2011',500)

truncate table #dates
create table #dates(
_month int,
_year int
)
insert into #dates values(10,2010)
insert into #dates values(11,2010) --missing month
insert into #dates values(12,2010)
insert into #dates values(01,2011)
insert into #dates values(02,2011)--missing month
insert into #dates values(03,2011)


select D._month, D._year, sum(amt)
from #dates D left join TABLE1 T on D._month=month(T.date) and D._year=year(T.date)
group by D._month, D._year
0 голосов
/ 21 февраля 2012
select sum(AMT) from TABLE1 group by Date
...