Неофициальный форум пользователей Qlik Sense & Qlikview

Для разработчиков => Вопросы по Qlik Sense & QlikView => Тема начата: HalLex от 15 октября 2017, 06:10:22

Название: Расчет даты последней покупки в скрипте Qlik Sense/Qlikview
Отправлено: HalLex от 15 октября 2017, 06:10:22
Доброго времени суток!

В своём примере расчета числа повторных покупок, Андрей Свиридов приводит такой вот код:


//***Автор скрипта Свиридов Андрей
ДанныеПродаж:
LOAD НомерСчета,
ДатаСчета,
КодКлиента,
sum(Сумма)as Сумма
FROM
Продажи.qvd (qvd)
Group By НомерСчета, ДатаСчета, КодКлиента;

//Используем резидентную загрузку для формирования таблицы с уникальными идентификаторами клиентов
Temp:
LOAD Distinct
КодКлиента as CustomerID
Resident ДанныеПродаж;
//В переменнуя Score будет записываться дата последнего счета по каждому клиенту

Set Score = 0;

//Первый цикл FOR перебирает каждого клиента в таблеце Temp

FOR i=0 to NoOfRows('Temp')-1
//В переменную Customer записывается идентификатор клиента на каждой итерации цикла
Let Customer = Peek('CustomerID',$(i),'Temp');

//Таблица Temp1 содержит даты всех счетов по каждому клиенту
Temp1:
NoConcatenate

Load
ДатаСчета as ДатаСчета1
Resident ДанныеПродаж
Where КодКлиента = '$(Customer)';//Каждый клиент попадает в параметр отбора

//Второй цикл вычисляет самую позднюю дату счета
FOR l=0 to NoOfRows('Temp1')-1
IF(Peek('ДатаСчета1',$(l),'Temp1')>$(Score)) then
LET Score = Peek('ДатаСчета1',$(l),'Temp1');//Дата счета записывается в переменную Score
ENDIF
NEXT;

DROP Table Temp1;//больше данные этой таблицы не нужны, она заполнится следующим клиентом на следующей итерации

//Формируем из данных переменных таблицу

Temp2:
LOAD
'$(Customer)' as Client,
'$(Score)' as LastDate
AutoGenerate (1);

SET Score = 0;//Присваиваем переменной значение 0, необходимо для последующей работы цикла

NEXT;

//присоединяем дополнительное поле к таблице по ключу "КодКлиента"

Left Join (ДанныеПродаж)
LOAD
Client as КодКлиента,
LastDate as ДатаПоследнегоСчета
Resident Temp2;

//Избавляемся от лишних таблиц

DROP Table Temp;
DROP Table Temp2;

//Создаем новую таблицу используя резидентную загрузку

Temp3:
NoConcatenate
LOAD
НомерСчета,
ДатаСчета,
КодКлиента,
Сумма,
ДатаПоследнегоСчета,
If(ДатаПоследнегоСчета<MonthEnd(AddMonths(Today(),-2)),1,0) as ПотеряныйКлиент,//Клиенты не совершившие покупку более месяца
If(ДатаПоследнегоСчета<MonthEnd(AddMonths(Today(),-2)),Num(Month(ДатаПоследнегоСчета)),) as МесяцПотериКлиента,// Месяц в котором клиент совершал последнюю покупку
If(ДатаПоследнегоСчета>MonthEnd(AddMonths(Today(),-2)),Num(Month(ДатаСчета)),) as МесяцНаличияКлиента//Месяц в котором клмент остается клиентом
Resident ДанныеПродаж;

//Убираем таблицу
DROP Table ДанныеПродаж;

//Переименовывыем таблицу
RENAME Table Temp3 to ДанныеПродаж;


В данном цикле, вычисляем самую позднюю дату счета. Подскажите пожалуйста, как преобразовать цикл, что бы вычислить наоборот, первую дату покупки?
Спасибо!!

FOR l=0 to NoOfRows('Temp1')-1
IF(Peek('ДатаСчета1',$(l),'Temp1')>$(Score)) then
LET Score = Peek('ДатаСчета1',$(l),'Temp1');//Дата счета записывается в переменную Score
ENDIF
Название: Re: Расчет даты последней покупки
Отправлено: admin от 16 октября 2017, 01:43:14
Привет, для чего использовать циклы?

Можно ведь сделать запрос на ID клиента и максимальную дату, т.о. мы получаем таблицу с ИД клиента и датой последней покупки. Т.е. получаем то же самое но намного быстрее и легче.
Название: Re: Расчет даты последней покупки
Отправлено: HalLex от 16 октября 2017, 02:42:15
А Вы могли бы привести пример такого кода (запроса)?
Название: Re: Расчет даты последней покупки
Отправлено: admin от 16 октября 2017, 03:17:03
LOAD
КодКлиента as CustomerID,
max(Дата) As ДатаКрайнейСделки
Resident ДанныеПродаж
group by КодКлиента;
Название: Re: Расчет даты последней покупки
Отправлено: HalLex от 16 октября 2017, 08:43:26
Решение прекрасно подошло для задачи, большое спасибо.

Подскажите, а есть решение, если мне требуется найти минимальный и максимальный интервал в днях, между покупками для покупателя?
Название: Re: Расчет даты последней покупки
Отправлено: admin от 17 октября 2017, 07:44:29
Сначала рассчитайте интервалы между покупками, затем рассчитывайте min, max.
Почитайте про previous & peek в хелпе (https://help.qlik.com/ru-RU/sense/June2017/Subsystems/Hub/Content/ChartFunctions/InterRecordFunctions/inter-record-functions-charts.htm)
Название: Re: Расчет даты последней покупки
Отправлено: HalLex от 18 октября 2017, 02:10:07
Подскажите, а как выполнять расчет именно для конкретного клиента из таблицы, а не все по порядку?

Test1:
Load
КодКлиента,
Date(ДатаСчета) as ДатаСчета1,
Previous (Date(ДатаСчета)) as Previuos,
ДатаСчета - Previous (Date(ДатаСчета)) as Разница
Resident DistClients
Order by КодКлиента;

Если брать простое использование функции, вычитается все по порядку. Соответственно, каждое последнее вычитание, это последняя покупка одного клиента и первая другого.
Название: Re: Расчет даты последней покупки
Отправлено: admin от 18 октября 2017, 03:20:54
Используйте проверку
load
...
if(КодКлиента=Previous(КодКлиента),
ДатаСчета - Previous (Date(ДатаСчета))) as Разница
...
Resident DistClients
Order by КодКлиента;
Название: Re: Расчет даты последней покупки
Отправлено: HalLex от 18 октября 2017, 05:32:07
Test1:
Load
КодКлиента,
Date(ДатаСчета) as ДатаСчета1,
Previous(ДатаСчета) as Previous,
if(КодКлиента = Previous(КодКлиента), ДатаСчета-Previous(Date(ДатаСчета))) as Разница
Resident DistClients
Order by КодКлиента, ДатаСчета;


MinMax:
Load
КодКлиента,
If(КодКлиента, Min(Разница)) as МинДнейМеждЗак,
If(КодКлиента, Max(Разница)) as МаксДнейМеждЗак
Resident Test1
Group by КодКлиента;

Для нахождения минимальной и максимальной разницы, решил так же использовать if. Максимум считает для каждого покупателя, а минимум только для некоторых, избирательно. Подскажите, в чем ошибка?
Название: Re: Расчет даты последней покупки
Отправлено: admin от 18 октября 2017, 07:18:33
Странно, что он вообще считает.
Зачем условия при группировке?
Просто вычисляйте минимум и максимум для клиента.
Название: Re: Расчет даты последней покупки
Отправлено: HalLex от 18 октября 2017, 08:28:49
Сначала так и пробовал, не группировать. Но ругается на выражение.




MinMax << Test1
Ошибка скрипта: Invalid expression
Произошла следующая ошибка:
Invalid expression
Ошибка произошла здесь:
MinMax:
Load
КодКлиента,
If(КодКлиента, Min(Разница)) as МинДнейМеждЗак,
If(КодКлиента, Max(Разница)) as МаксДнейМеждЗак
Resident Test1
Произошла следующая ошибка:
Invalid expression
Ошибка произошла здесь:
?
Данные не загружены. Исправьте ошибку и повторите загрузку.
Название: Re: Расчет даты последней покупки
Отправлено: admin от 19 октября 2017, 03:38:55
мин и макс работают только при группировке.
Название: Re: Расчет даты последней покупки
Отправлено: HalLex от 19 октября 2017, 07:23:24
Load
КодКлиента,
Min(Разница) as МинДнейМеждЗак,
Max(Разница) as МаксДнейМеждЗак
Resident Test1
Group By КодКлиента;

Спасибо!!!
Название: Re: Расчет даты последней покупки
Отправлено: HalLex от 20 октября 2017, 05:40:27
Возник еще вопрос по ходу.... Не могу сообразить, как мне объяснить функции autonumber, пронумеровать дату первой покупки для каждого покупателя. Есть код клиента, есть даты его покупок, есть дата первой покупки. Идея в том, что бы присвоить "1" первой его покупке, для определения количества новых покупателей за выбранную дату покупки. Либо пронумеровать каждую дату покупки (1,2,3.....), но так для каждого покупателя, начиная с "1".
Название: Re: Расчет даты последней покупки
Отправлено: HalLex от 12 ноября 2017, 01:24:31
НумерацияПокупок:
   LOAD
   Distinct (КодКлиента) as ClientID,
   ДатаСчета as DateSale,
   AutoNumber(ДатаСчета,[КодКлиента])
   resident DistClients;

Вроде как разобрался)