Использование макроса в выражении

Автор d.pimkin, 03 марта 2015, 11:56:48

« назад - далее »

d.pimkin

Доброго времени суток!

Очень интересует следующий вопрос:
Можно ли как-нибудь использовать пользовательские функции, написанные в редакторе макросов, в выражениях (конкретно интересует прямая таблица)?
Бесчисленные попытки приводили только к следующему сообщению: "Error: Error in expression: function_name is not a valid function". В самом редакторе макросов все работает.
Разумеется, проверял даже на бональных a+b.

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

И еще один вопрос в догонку: можно ли в скрипте загрузки использовать макросы, обращающиеся к уже загруженным полям? Читал на форумах, что, вроде как, нельзя, но можно ли как-то это обойти? Либо можно в макросе обращаться к qvd файлам?

admin

Привет.
Теоретически, да. Но фактически нет. Ядро каждый раз пересчитывает выражения при смена состояния, представьте что будет, если еще и макросы обрабатывать каждый раз.
Пересмотрите задачу на предмет предварительного расчета параметров.
То же самое и по второму вопросу.
Надо проанализировать задачу в комплексе от источников до результата.

SimonAstakhov

#2
d.pimkin, есть довольно простой способ просчитать данные макросом и отобразить в отчёте.

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

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

Rem Dynamic Data Update

sub Update
  SET Result = ActiveDocument.DynamicUpdateCommand ("UPDATE * SET Discount = if(Discount >= 35, 0, if (City='Stockholm', Discount + 5, Discount + 2)) WHERE Country = 'SE'")
  if Result = false then
    MsgBox Result.ErrorMessage
  end if 
end sub

sub Insert
  SET Result = ActiveDocument.DynamicUpdateCommand ("INSERT INTO * (Country, City) VALUES (DK, Copenhagen), (NO, Oslo)")
  if Result = false then
    MsgBox Result.ErrorMessage
  end if 
end sub

sub Delete
  SET Result = ActiveDocument.DynamicUpdateCommand ("DELETE FROM CITY WHERE IsNull (Discount)")
  if Result = false then
    MsgBox Result.ErrorMessage
  end if 
end sub

d.pimkin

В таком случае, не могли бы помочь решить задачу не используя макросы?

Задача:
Имеется таблица событий для каждого triggerid следующего типа


value: 1 - состояние DOWN, 0 - состояние UP.
Также есть 2 переменные vFromDate и vToDate, обозначающие начало и конец отчетного периода. Они меняются календарем.

Необходимо для каждого triggerid посчитать процент доступности/недоступности за отчетный период. В общем случае формула для подсчета процента недоступности выглядит так:
Interval(sum({<value = {'1'},time = {'>=$(vFromDate)<=$(vToDate)'}>}diff),'s')/Interval(vToDate-vFromDate,'s')
Однако тут не учитывается несколько частных случаев:
1)Если за период не было событий, необходимо вычислить значение поля value максимального time меньшего vFromDate. Если такого не существует - Null, если value=0 - 0 (0%), value=1 - 1 (100%).
2)Если у первого события за период value=0 (т.е. он поднялся), значит от начала периода до первого события он был в состоянии down, следовательно это тоже надо как-то учесть. А в общей формуле это вообще не учитывается.
3)Если у последнего события за период value=1 (т.е. он упал), значит до конца периода он был в состоянии down, однако по общей формуле он плюсует разницу до следующего события (которое было точно позже vToDate), т.е. плюсует лишнее время.

Как эту задачу решить через макрос, я представляю. Однако, пользовательские формулы в выражениях не работают.

admin

Вариант с растягиванием значений Value посекундно не рассматривали?
Будет всего три поля, triggerid, time, value.
Соответственно и подход другой. Минус в количестве записей.

SimonAstakhov

1)Если за период не было событий, необходимо вычислить значение поля value максимального time меньшего vFromDate. Если такого не существует - Null, если value=0 - 0 (0%), value=1 - 1 (100%).
if(count({<time = {'>=$(vFromDate)<=$(vToDate)'}>}triggerid), FirstSortedValue({<time={'<=$(vFromDate)'}>} value, -time))
2)Если у первого события за период value=0 (т.е. он поднялся), значит от начала периода до первого события он был в состоянии down, следовательно это тоже надо как-то учесть. А в общей формуле это вообще не учитывается.
if(FirstSortedValue({<time = {'>=$(vFromDate)<=$(vToDate)'}>} value, time)=0, min({<time = {'>=$(vFromDate)<=$(vToDate)'}>}time)-$(vFromDate))
3)Если у последнего события за период value=1 (т.е. он упал), значит до конца периода он был в состоянии down, однако по общей формуле он плюсует разницу до следующего события (которое было точно позже vToDate), т.е. плюсует лишнее время.
Аналогично второму решению.

Код писал прямо тут, так что может сразу не завестись, но общую логику и как соединить, думаю решите самостоятельно. А так, в общем, в следующий раз давайте ссылку на семпл проблемы, тогда будет проще увидеть и понять проблему и передать решение.

d.pimkin

SimonAstakhov, спасибо большое! Не знал о функции FirstSortedValue. В итоге код получился очень объемным,но считает, как надо! Учел все частные случаи...

Если кому интересно, код приложил.

if (
FirstSortedValue(time, time)>vToDate, //первое событие за историю произошло позже vToDate
Null(),
if(
Count({<time = {'>=$(vFromDate)<=$(vToDate)'}>}time)=0, //количество событий за период равно 0
if(
FirstSortedValue({<time={'<=$(vFromDate)'}>} value, -time)=1, //значение последнего события до vFromDate равно 1, т.е. упал
1, //100%
if(
FirstSortedValue({<time={'<=$(vFromDate)'}>} value, -time)=0, //значение последнего события до vFromDate равно 0, т.е. поднялся
0) //0%
),
if(
FirstSortedValue(time, time)<vFromDate, //первое событие за историю произошло раньше vFromDate
if(
FirstSortedValue({<time = {'>=$(vFromDate)<=$(vToDate)'}>} value, time)=0 OR FirstSortedValue({<time = {'>=$(vFromDate)<=$(vToDate)'}>} value, -time)=1, //знач. первого события за период равно 0, т.е. поднялся ИЛИ знач. посл. события за период равно 1, т.е. упал (если частный случай)
if(
FirstSortedValue({<time = {'>=$(vFromDate)<=$(vToDate)'}>} value, time)=0 AND FirstSortedValue({<time = {'>=$(vFromDate)<=$(vToDate)'}>} value, -time)=1, //знач. первого события за период равно 0, т.е. поднялся И знач. посл. события за период равно 1, т.е. упал
if(
FirstSortedValue({<time={'<=$(vFromDate)'}>} value, -time)=1, //значение последнего события до vFromDate равно 1, т.е. упал
(Interval(sum({<value = {'1'},time = {'>=$(vFromDate)<=$(vToDate)'}>}diff),'s')+Interval(min({<time = {'>=$(vFromDate)<=$(vToDate)'}>}time)-vFromDate,'s')-Interval(FirstSortedValue({<time={'>=$(vFromDate)<=$(vToDate)'}>} nexttime, -nexttime)-vToDate,'s'))/Interval(vToDate-vFromDate,'s'), //сумма diff +Разница между vFromDate и первым событием -Разница между vToDate и первым соб. после
(Interval(sum({<value = {'1'},time = {'>=$(vFromDate)<=$(vToDate)'}>}diff),'s')-Interval(FirstSortedValue({<time={'>=$(vFromDate)<=$(vToDate)'}>} nexttime, -nexttime)-vToDate,'s'))/Interval(vToDate-vFromDate,'s')
),
if(
FirstSortedValue({<time = {'>=$(vFromDate)<=$(vToDate)'}>} value, time)=0,//знач. первого события за период равно 0, т.е. поднялся
if(
FirstSortedValue({<time={'<=$(vFromDate)'}>} value, -time)=1, //значение последнего события до vFromDate равно 1, т.е. упал
(Interval(sum({<value = {'1'},time = {'>=$(vFromDate)<=$(vToDate)'}>}diff),'s')+Interval(min({<time = {'>=$(vFromDate)<=$(vToDate)'}>}time)-vFromDate,'s'))/Interval(vToDate-vFromDate,'s'), //сумма diff +Разница между vFromDate и первым событием
Interval(sum({<value = {'1'},time = {'>=$(vFromDate)<=$(vToDate)'}>}diff),'s')/Interval(vToDate-vFromDate,'s')
),
if(
FirstSortedValue({<time = {'>=$(vFromDate)<=$(vToDate)'}>} value, -time)=1, //знач. посл. события за период равно 1, т.е. упал
if(
FirstSortedValue({<time={'<=$(vFromDate)'}>} value, -time)=1, //значение последнего события до vFromDate равно 1, т.е. упал
(Interval(sum({<value = {'1'},time = {'>=$(vFromDate)<=$(vToDate)'}>}diff),'s')+Interval(min({<time = {'>=$(vFromDate)<=$(vToDate)'}>}time)-vFromDate,'s')-Interval(FirstSortedValue({<time={'>=$(vFromDate)<=$(vToDate)'}>} nexttime, -nexttime)-vToDate,'s'))/Interval(vToDate-vFromDate,'s'),
(Interval(sum({<value = {'1'},time = {'>=$(vFromDate)<=$(vToDate)'}>}diff),'s')-Interval(FirstSortedValue({<time={'>=$(vFromDate)<=$(vToDate)'}>} nexttime, -nexttime)-vToDate,'s'))/Interval(vToDate-vFromDate,'s') //сумма diff -Разница между vToDate и первым соб. после
),
)
)
),
if(
FirstSortedValue({<time={'<=$(vFromDate)'}>} value, -time)=1, //значение последнего события до vFromDate равно 1, т.е. упал
(Interval(sum({<value = {'1'},time = {'>=$(vFromDate)<=$(vToDate)'}>}diff),'s')+Interval(min({<time = {'>=$(vFromDate)<=$(vToDate)'}>}time)-vFromDate,'s'))/Interval(vToDate-vFromDate,'s'),
Interval(sum({<value = {'1'},time = {'>=$(vFromDate)<=$(vToDate)'}>}diff),'s')/Interval(vToDate-vFromDate,'s') //общий случай
)
),
if(
FirstSortedValue({<time = {'>=FirstSortedValue(time, time)<=$(vToDate)'}>} value, time)=0 OR FirstSortedValue({<time = {'>=FirstSortedValue(time, time)<=$(vToDate)'}>} value, -time)=1, //знач. первого события за период равно 0, т.е. поднялся ИЛИ знач. посл. события за период равно 1, т.е. упал (если частный случай)
if(
FirstSortedValue({<time = {'>=FirstSortedValue(time, time)<=$(vToDate)'}>} value, time)=0 AND FirstSortedValue({<time = {'>=FirstSortedValue(time, time)<=$(vToDate)'}>} value, -time)=1, //знач. первого события за период равно 0, т.е. поднялся И знач. посл. события за период равно 1, т.е. упал
(Interval(sum({<value = {'1'},time = {'>=FirstSortedValue(time, time)<=$(vToDate)'}>}diff),'s')+Interval(min({<time = {'>=FirstSortedValue(time, time)<=$(vToDate)'}>}time)-FirstSortedValue(time, time),'s')-Interval(FirstSortedValue({<time={'>=FirstSortedValue(time, time)<=$(vToDate)'}>} nexttime, -nexttime)-vToDate,'s'))/Interval(vToDate-FirstSortedValue(time, time),'s'), //сумма diff +Разница между FirstSortedValue(time, time) и первым событием -Разница между vToDate и первым соб. после
if(
FirstSortedValue({<time = {'>=FirstSortedValue(time, time)<=$(vToDate)'}>} value, time)=0,//знач. первого события за период равно 0, т.е. поднялся
(Interval(sum({<value = {'1'},time = {'>=FirstSortedValue(time, time)<=$(vToDate)'}>}diff),'s')+Interval(min({<time = {'>=FirstSortedValue(time, time)<=$(vToDate)'}>}time)-FirstSortedValue(time, time),'s'))/Interval(vToDate-FirstSortedValue(time, time),'s'), //сумма diff +Разница между vFromDate и первым событием
if(
FirstSortedValue({<time = {'>=FirstSortedValue(time, time)<=$(vToDate)'}>} value, -time)=1, //знач. посл. события за период равно 1, т.е. упал
(Interval(sum({<value = {'1'},time = {'>=FirstSortedValue(time, time)<=$(vToDate)'}>}diff),'s')-Interval(FirstSortedValue({<time={'>=FirstSortedValue(time, time)<=$(vToDate)'}>} nexttime, -nexttime)-vToDate,'s'))/Interval(vToDate-FirstSortedValue(time, time),'s') //сумма diff -Разница между vToDate и первым соб. после
)
)
),
Interval(sum({<value = {'1'},time = {'>=FirstSortedValue(time, time)<=$(vToDate)'}>}diff),'s')/Interval(vToDate-FirstSortedValue(time, time),'s') //общий случай
)
)
)
)

Яндекс.Метрика