Хранилища данных,
OLAP, CRM: информация
 
 На главную | Книги | Ссылки | Рассылка | Письмо автору | RSS

Совет №23
Скользящее предсказание будущего, сейчас и в прошлом

Материал опубликован с разрешения компании Ralph Kimball Associates
Автор оригинала: Ральф Кимбалл (все статьи)
Перевод на русский язык: Константин Лисянский
Оригинальный документ располагается здесь.

В этом совете я описываю симпатичную и несколько замысловатую загадку, присланную мне Ричардом Томлинсоном из компании Business Objects. Его пользователям было необходимо выбрать произвольный день (в пределах следующих нескольких месяцев) в будущем, а затем, смотря назад от того дня, подготовить отчёт сегодняшнего дня до этого дня в будущем. И этого не было достаточно, поскольку пользователям иногда нужно было переопределить СЕГОДНЯ на произвольный день (в пределах нескольких прошедших месяцев) в прошлом! Предельно ясно, да? Текст совета будет представлять нашу слегка отредактированную переписку.

>>>> Исходное сообщение Ральфу от Ричарда с описанием проблемы <<<<

Привет, Ральф и Ко.
Помогите! Я, в самом деле, застрял, но это интересный вопрос проектирования для тех, кто чувствует в себе силы:
Как мне предсказать будущее? Мне нужно спроектировать симпатичную простую (ха-ха) таблицу фактов...

У меня в витрине данных есть таблица измерения СЧЁТ, в которой имеется поле 'Status', скажем статус "просрочен". Я также знаю 'дату статуса', скажем 2 мая 2001 года.
Бизнес-пользователь хочет знать следующее: СКОЛЬКО ДНЕЙ СЧЁТ БУДЕТ НАХОДИТЬСЯ В СОСТОЯНИИ "ПРОСРОЧЕН" В СЛЕДУЮЩЕМ МЕСЯЦЕ?

Если СЕГОДНЯ 5 мая 2001 года, пользователь хочет видеть следующее:
5 мая: 4 дня
6 мая: 5 дней
7 мая: 6 дней
и т.д. до 4 июня 2001 г. - это нарастающий месяц в будущем, начинающийся СЕГОДНЯ.

Дальше они хотят сосчитать все счета в таблице счетов и сгруппировать их по интервалам в днях со статусом 'ПРОСРОЧЕНО' чтобы увидеть следующее:
5 мая: 100 счетов - 4-6 дней 'ПРОСРОЧЕНО'
6 мая: 78 счетов - 4-6 дней 'ПРОСРОЧЕНО'
и т.д.
5 мая: 200 счетов - 7-9 дней 'ПРОСРОЧЕНО'
6 мая: 245 счетов - 7-9 дней 'ПРОСРОЧЕНО'
и т.д.

Мне также нужно путешествовать назад во времени и делать то же самое для любого момента времени + 1 месяц, однако, у многих счетов будут установлены даты 'Status_Ineffective_Date', и они уже никогда не будут иметь статус 'ПРОСРОЧЕНО', но для них будут существовать исторические записи в таблице счетов для того, чтобы показать, когда они имели этот статус через медленно изменяющееся измерение типа 2.

Если у кого-либо имеется подобный опыт с такой проблемой, или если кто-то знает, как решить её, пожалуйста, дайте мне знать... у меня болит голова.

С уважением,
Ричард.

>>>> Ответ Ральфа Ричарду <<<<

Привет, Ричард.
Я взглянул на это. Может быть, следующее сработает.
Предположим, что твоя таблица измерения счетов имеет следующие поля (как ты описывал):
ACCOUNT_KEY
STATUS
STATUS_EFFECTIVE_DT
Теперь построим ещё одну таблицу со следующими полями:
STATUS_EFFECTIVE_DT
STATUS_REPORTING_DT
DELTA
где DELTA - это количество дней между эффективной датой и датой отчёта. В этой таблице должны быть данные для любых комбинаций эффективных дат и дат отчёта, в которых могут быть заинтересованы твои пользователи. Если эффективные даты уходят в прошлое на 1 год (365 дней), и ты хочешь выполнять отчёты на 1 год вперёд, то в этой таблице понадобится 365*365 или около 130000 строк. Могут быть и другие предположения. Достаточно много, но может быть работоспособно, если имеется достаточно много памяти.

В любом случае, соедини эту вторую таблицу с первой по полю STATUS_EFFECTIVE_DT.
Тогда твой первый запрос можно удовлетворить с помощью следующего:

SELECT STATUS_REPORTING_DT, DELTA
FROM .
WHERE STATUS='OVERDUE'
AND STATUS_REPORTING_DT BETWEEN 'May 5, 2001' and 'June 4, 2001'
ORDER BY STATUS_REPORTING_DT

Для получения отчёта с разбивкой на периоды, возможно, ты построишь третью таблицу (таблицу периодов) с полями
BAND_NAME
UPPER_DELTA
LOWER_DELTA

Соедини эту таблицу со второй по условию
DELTA<=UPPER_DELTA
DELTA>LOWER_DELTA

У тебя получится SQL наподобие этого:
SELECT BAND_NAME, COUNT(*)
FROM (все три таблицы, соединённые как было описано)
WHERE STATUS_REPORTING_DT BETWEEN 'May 5, 2001' and 'June 4, 2001'
AND DELTA<=UPPER_DELTA
AND DELTA>LOWER_DELTA
ORDER BY UPPER_DELTA
GROUP BY BAND_NAME

Я описываю этот подход к интервалам в книге Lifecycle Toolkit на страницах 251-252. Попробуй его на небольшой тестовой базе Access. Расскажи о том, что получится.

Удачи.
Ральф Кимбал


>>>> Последующий ответ Ричарда после того, как он опробовал решение <<<<

Привет, Ральф.
Мне доставляет удовольствие сообщить, что твоё решение сработало! Спасибо. Я опробовал его на нескольких тестовых строках в SQL Server 7.0, и результаты выглядели хорошо. Я продвинул его на следующий уровень, включив Status_Ineffective_Date чтобы иметь возможность исключить те счета, которые остановили статус 'ПРОСРОЧЕНО' где-то в отчётном периоде. Может быть, тебе захочется опубликовать это в одном из писем твоей рассылки?

Для начала, я несколько изменил твой SQL, приведя его к следующему виду:
SELECT
COUNT(account.Account_Id),
days_overdue.reporting_date
FROM
account,
days_overdue
WHERE
(account.Status_Effective_Date=days_overdue.effective_date)
AND
(days_ovedue.reporting_date BETWEEN '05/05/2001' AND '06/04/2001' AND days_overdue.delta>= 10 {произвольное число или интервал, которые пользователь выбирает при запуске отчёта}
)
GROUP BY
days_overdue.reporting_date

Ключевым моментом запроса является ограничение по 'дельте' (которую мы называем 'days_overdue'), в противном случае запрос вернёт каждый счёт для каждого дня отчётного периода, а функция COUNT будет возвращать всё время одно и то же число. Ограничение должно быть по равенству, неравенству или вхождению в диапазон, но оно должно обязательно присутствовать.

Во-вторых, для исключения счетов, которые более не являются просроченными (мы предполагаем, что знаем дата, когда они будут оплачены или были оплачены!), мы просто включаем в таблицу счетов поле status_ineffective_date, после чего можем сделать следующее:
SELECT
COUNT(account.Account_Id),
days_overdue.reporting_date
FROM
account,
days_overdue
WHERE
(account.Status_Effective_Date=days_overdue.effective_date)
AND
(days_ovedue.reporting_date BETWEEN '05/05/2001' AND '06/04/2001' AND days_overdue.delta>= 10
AND account.status_ineffective_date>days_overdue.reporting_date
)
GROUP BY
days_overdue.reporting_date

Естественно, вам придётся установить ineffective_date для всех просроченных в настоящее время счетов в какую-то величину в будущем, например 01.01.3000. Это также хорошо вписывается в концепцию SCD типа 2, когда мы создаём новую строку в таблице измерения счёт каждый раз при изменении статуса, чтобы предоставить возможность полного исторического сравнения!

Спасибо большое за помощь. С наилучшими пожеланиями,
Ричард Томлинсон

>>>> Финальный постскриптум <<<<

Это была небольшая весёлая головоломка. Очень здорово получать такие, но если шлёте мне запрос, пожалуйста, будьте понимающими! Я, естественно, не могу рассмотреть их все, и в некоторых случаях результаты не будут такими славными.

С уважением,
Ральф

Ральф Кимбал ralph@ralphkimball.com

 

 

Для удобства отслеживания новых публикаций на сайте рекомендую подписаться на рассылку или подписаться на канал RSS.

 

Если вы нашли в сети интересные ссылки на ресурсы по технологиям хранилищ данных, OLAP, CRM или data mining, и хотите поделиться ими с другими, присылайте их. Я с удовольствием размещу их на этом сайте.

Популярные страницы:

Советы разработчику хранилищ данных

OLAP

Моделирование

Книги

Книги на русском языке

Бесплатные книги

Производители OLAP

CRM

Производители CRM

Управление метаданными

Коллекция ссылок


Найти: на

[ На главную | Книги | Ссылки | Рассылка | Письмо автору | Реклама на сайте ]

© Константин Лисянский, 2001-2008.

SpyLOG Rambler's Top100 Rambler's Top100

Используются технологии uCoz