SQL Rolling Total до определенной даты

62
8

У меня есть две таблицы, с которыми я работаю. Позвольте называть их "Клиенты" и "Баллы".

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

Account Year M01 M02 M03 M04 M05 M06 M07 M08 M09 M10 M11 M12
123 2011 10 0 0 0 10 0 10 0 0 0 0 10
123 2012 0 0 0 0 10 0 0 10 10 10 10 20
123 2013 5 0 0 0 0 0 0 0 0 0 0 0

Но эти моменты работают в течение 12 месяцев. Вычисление текущих клиентских точек достаточно просто, но задача заключается в том, что клиенты больше не активны. Скажем, клиент 123 стал неактивным в январе 2013 года, мы хотели бы рассчитать февраль-12 января. Здесь приходит другая таблица "Клиенты", позволяет упростить и сказать, что она выглядит так:

Account   End Date
123 20130105

Теперь я хочу создать запрос, который вычисляет количество баллов, которое имеет каждый клиент. (Текущие 12 месяцев для активных клиентов, последние 12 месяцев они были активны для клиентов, которые больше не активны).

Вот еще информация:

    Я запускаю SQL Server 2008. Эти таблицы были предоставлены мне так, я не могу их модифицировать. Активным клиентом является тот, у кого есть дата окончания 99991231 (31 декабря 9999 года) Таблица точек только заполняет годами, что клиент является активным клиентом. Ака, кто-то становится активным клиентом в феврале 2009 года, у них есть запись на 2009 год, если они стали неактивными в июле 2009 года, их очки рассчитываются только в феврале-июле 2009 года, в 2008 году нет ни одной строки, поскольку они не были клиентом Тогда. Jan & Aug-Dec 2009 покажут 0. Кроме того, запись создается только в том случае, если клиент набирает очки в этом году. Если клиент получает 0 очков в год, записи об этом не будет. Для пограничных случаев, если вы попадаете в первый день месяца, подсчитывается этот месяц. Пример, допустим, сегодня - 1 апреля 2013 года, это означает, что мы подытожим май'12-апрель'13.

Это довольно сложный вопрос. Если что-нибудь я могу объяснить лучше, пожалуйста, дайте мне знать. Спасибо!

спросил(а) 2021-01-19T16:36:16+03:00 2 месяца, 3 недели назад
1
Решение
98

К сожалению, с вашей табличной структурой points вам придется отключать данные. Неповтор берет данные из нескольких столбцов в строки. После того, как данные находятся в строках, будет гораздо проще вступить, фильтровать данные и суммировать баллы для каждой учетной записи. Код для отключения данных будет аналогичен этому:

select account,
cast(cast(year as varchar(4))+'-'+replace(month_col, 'M', '')+'-01' as date) full_date,
pts
from points
unpivot
(
pts
for month_col in ([M01], [M02], [M03], [M04], [M05], [M06], [M07], [M08], [M09], [M10], [M11], [M12])
) unpiv

См. SQL Fiddle with Demo. Запрос дает результат, подобный этому:

| ACCOUNT |  FULL_DATE | PTS |
------------------------------
| 123 | 2011-01-01 | 10 |
| 123 | 2011-02-01 | 0 |
| 123 | 2011-03-01 | 0 |
| 123 | 2011-04-01 | 0 |
| 123 | 2011-05-01 | 10 |

Как только данные будут в этом формате, вы можете присоединиться к таблице Customers чтобы получить общие баллы для каждой account, поэтому код будет похож на следующий:

select 
c.account, sum(pts) TotalPoints
from customers c
inner join
(
select account,
cast(cast(year as varchar(4))+'-'+replace(month_col, 'M', '')+'-01' as date) full_date,
pts
from points
unpivot
(
pts
for month_col in ([M01], [M02], [M03], [M04], [M05], [M06], [M07], [M08], [M09], [M10], [M11], [M12])
) unpiv
) p
on c.account = p.account
where
(
c.enddate = '9999-12-31'
and full_date >= dateadd(year, -1, getdate())
and full_date <= getdate()
)
or
(
c.enddate <> '9999-12-31'
and dateadd(year, -1, [enddate]) <= full_date
and full_date <= [enddate]
)
group by c.account

См. SQL Fiddle with Demo

ответил(а) 2021-01-19T16:36:16+03:00 2 месяца, 3 недели назад
75

Отвратительная структура данных. Первое, что нужно сделать, это раскрыть его. Затем вы получаете таблицу с месяцами года в качестве столбцов.

Отсюда вы можете выбрать последние 12 месяцев. На самом деле вам даже не нужно беспокоиться о том, когда клиент ушел, поскольку, по-видимому, они не собирали баллы с тех пор.


Вот пример в SQL:

with points as (
select 123 as account, 2012 as year,
10 as m01, 0 as m02, 0 as m03, 0 as m04, 10 as m05, 0 as m06,
10 as m07, 0 as m08, 0 as m09, 0 as m10, 0 as m11, 10 as m12
),
points_ym as (
select account, YEAR, mon, cast(right(mon, 2) as int) as monnum, points
from points
unpivot (points for mon in (m01, m02, m03, m04, m05, m06, m07, m08, m09, m10, m11, m12)
) as unpvt
)
select account, SUM(points)
from points_ym
where year*12+monnum >= year(getdate())*12+MONTH(getdate()) - 12
group by account

ответил(а) 2021-01-19T16:36:16+03:00 2 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема