Процедуры, sub, подпрограммы
Функции упрощают работу в скриптах Qlik Sense, но в то же время и усложняют чтение кода
LinkTable
Таблица связей (link table)
Известно, что для правильной работы модели данных, таблицы должны быть соединены между собой только 1 полем, а что делать если у нас в 2 или более таблицах от 2 одинаковых полей? Мы же не хотим держать SSyn-таблицы внутри модели? Иначе у нас будут не верные расчёты..
Тут нам на помощь приходит функция создания промежуточной таблицы связей между таблицами. Помните, что функции должны быть написаны в скрипте ранее, чем они будут вызваны. Синтаксис:
CALL LinkTable ('имя новой или существующей таблицы связей', 'имя таблицы из которой нужно забрать поля', 'поля перечисленные через запятую' );
Например, написав 2 строчки в коде, мы сделаем связи между 2 таблицами по 3 полям:
CALL LinkTable ('plan-fact_link', 'table_sales', 'period, id_goods, id_shop');
CALL LinkTable ('plan-fact_link', 'table_plan', 'period, id_goods, id_shop');
Результатом выполнения функций - будет новая таблица, в которой будет ключевое поле и 3 поля из 2 таблиц, в основных таблицах останется только ключевое поле
На ключевое поле - используется функция AUTONUMBER() для оптимизации работы Qlik Engine, и уменьшения объемов данных
Результат выполнения функции в модели данных:
скрипт функции
SUB LinkTable (ls_linkTableName, ls_table, ls_fields)
// Генерируем произвольное наименование временной таблицы
LET ls_LinkTableTemp = '$(ls_linkTableName)' & '_temp_' & KEEPCHAR(NOW(),'0123456789');
[$(ls_LinkTableTemp)]:
NOCONCATENATE LOAD DISTINCT
$(ls_fields),
AutoNumberHash128('$(ls_fields)',$(ls_fields)) as [%$(ls_linkTableName)_Key]
RESIDENT $(ls_table);
LEFT JOIN ($(ls_table)) // Join key from link table to source table
LOAD [%$(ls_linkTableName)_Key], $(ls_fields) RESIDENT [$(ls_LinkTableTemp)];
DROP FIELDS $(ls_fields) FROM $(ls_table);
IF NOT ISNULL(TableNumber('$(ls_linkTableName)')) THEN
OUTER JOIN ([$(ls_linkTableName)])
LOAD * RESIDENT [$(ls_LinkTableTemp)];
DROP TABLE [$(ls_LinkTableTemp)];
ELSE
RENAME TABLE [$(ls_LinkTableTemp)] TO [$(ls_linkTableName)];
ENDIF
SET ls_LinkTableTemp=;
// Применяем AUTONUMBER для сокращения объема данных по нашему ключевому полю
AUTONUMBER [%$(ls_linkTableName)_Key] USING '$(ls_linkTableName)';
END SUB;
скрипт генерации тестовых данных
Код должен быть расположен после написания кода функции
LET varPeriodStart = NUM(Today() - 60);
table_sales:
LOAD
DATE(FLOOR($(varPeriodStart) + (rand() * 60))) AS period
, floor(rand()*150)+1 AS id_goods
, floor(rand()*10)+1 AS id_shop
, floor(rand() * 1000) + 10 AS fact_sales
, floor(rand() * 20) + 1 AS fact_quant
AUTOGENERATE 10000
;
table_plan:
LOAD
DATE(FLOOR($(varPeriodStart) + (rand() * 60))) AS period
, floor(rand()*150)+1 AS id_goods
, floor(rand()*10)+1 AS id_shop
, floor(rand() * 1000) + 10 AS plan_sales
, floor(rand() * 20) + 1 AS plan_quant
AUTOGENERATE 10000
;
table_goods:
LOAD
FIELDVALUE ('id_goods', RowNo()) as id_goods
, 'good_' & FIELDVALUE ('id_goods', RowNo()) as goods_name
AUTOGENERATE FIELDVALUECOUNT ('id_goods');
table_shops:
LOAD
FIELDVALUE ('id_shop', RowNo()) as id_shop
, 'shop_' & FIELDVALUE ('id_shop', RowNo()) as shop_name
AUTOGENERATE FIELDVALUECOUNT ('id_shop');
CALL LinkTable ('plan-fact_link', 'table_sales', 'period, id_goods, id_shop');
CALL LinkTable ('plan-fact_link', 'table_plan', 'period, id_goods, id_shop');
Создание календаря
GetUniqueValues
- Получить таблицу с уникальными значениями по одному полю
Создает таблицу с набором уникальных значений поля (допускается преобразование поля и агрегация)
Параметры:
- _fieldName - поле в модели (не в конкретной таблице)
- _tableName - имя таблицы-приемника уникальных значений поля _fieldName
- _destinationFieldName - имя поля-приемника уникальных значений поля _fieldName
- _transformOperator - содержит выражение для преобразования значения поля _fieldName.
примеры использования
Создай таблицу Factor
из поля _factorName
, уникальные значения запиши в поле ExpressFactor_
, примени функцию NUM()
к этому полю
Call GetUniqueValues('_factorName', 'Factor', 'ExpressFactor_', 'Num');
скрипт функции
SUB GetUniqueValues(_fieldName, _tableName, _destinationFieldName, _transformOperator)
LET lib_vTransformOperator = $(eDefaultIfEmpty(_transformOperator, ''));
LET lib_vExpression = If(Index(lib_vTransformOperator, '{expression}')
,Replace(lib_vTransformOperator, '{expression}', 'FieldValue('&chr(39)&'$(_fieldName)'&chr(39)&', RecNo())')
,lib_vTransformOperator & '(FieldValue('&chr(39)&'$(_fieldName)'&chr(39)&', RecNo()))');
LET lib_vDistinctValuesQty = FieldValueCount(_fieldName);
NoConcatenate [$(_tableName)]:
LOAD Distinct
$(lib_vExpression) AS [$(_destinationFieldName)]
AutoGenerate $(lib_vDistinctValuesQty);
SET lib_vDistinctValuesQty;
SET lib_vTransformOperator;
SET lib_vExpression;
END SUB
eNumberMinMaxToVariable
, eNumberMinToVariable
, eNumberMaxToVariable
- получить min/max из 1 поля в модели в переменную
Процедура для расчета минимального и максимального значений поля
Удобно использовать через макроподстановку: eNumberMinMaxToVariable
, eNumberMinToVariable
, eNumberMaxToVariable
Параметры:
- _field_name поле со значениями
- variable_name[min, max] -переменная - приемник результата
Для работы требует наличие подпрограммы(sub,процедуры) GetUniqueValues
примеры использования
Возьми все уникальные значения в поле FileDate
и запиши результаты в переменные vMinValue
и vMaxValue
$(eNumberMinMaxToVariable('FileDate', 'vMinValue', 'vMaxValue'));
Возьми все уникальные значения в поле FileDate
и запиши результат минимального значения в переменную vMinValue
$(eNumberMinToVariable('FileDate', 'vMinValue'));
Возьми все уникальные значения в поле FileDate
и запиши результат максимального значения в переменную vMaxValue
$(eNumberMaxToVariable('FileDate', 'vMaxValue'));