Скрипт для суммирования данных не обновляется

У меня есть таблица данных табеля Google; у него есть лист для каждого месяца, каждый лист состоит из шести блоков столбцов, по одному блоку на клиента.

Я создал сводную таблицу, которая получает и получает общую сумму для каждого клиента и отображает ее в виде списка:

function getClientTotals(sheetname, colcount)
{  
  colcount = colcount ? colcount : 6;
  var res;      
  var ss = SpreadsheetApp.openById('myid_goes_here');
  if(ss)
  {
    res = [];
    var totrow = ss.getRange(sheetname + '!A1:ZZ1').getValues()[0];
    for(var i = 0; i < totrow.length; i += colcount)
    {
      res.push([totrow[i], totrow[i + colcount - 1]]);
    }
  }   
  return res;
}

Затем я просто добавил в свой сводный листок ячейку, содержащую =getClientTotals($C$7,$C$8) который передает имя листа за месяц и количество столбцов для каждого клиента (в случае изменения схемы).

Это все работает нормально, однако, оно не обновляется при изменении исходных данных. Я добавил onEdit спусковой крючок; нет радости Он обновляется, если вы идете в редактор скриптов и нажимаете Сохранить, но это бесполезно. Я что-то пропустил?

8 ответов

Решение

Вам не хватает привередливой функции кеширования. Это работает так:

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

Учитывая эту предпосылку, они могут оценивать ваши функции только при изменении параметра. например

Давайте предположим, что у нас есть текст "10" в ячейке B1, а затем в какой-то другой ячейке мы набираем =myFunction(B1)

myFunction будет оценена и ее результат получен. Затем, если вы измените значение ячейки B1 на "35", пользовательский будет переоценен, как ожидается, и новый результат будет получен в обычном режиме. Теперь, если вы снова измените ячейку B1 на исходную "10", переоценка не производится, исходный результат немедленно извлекается из кэша.

Поэтому, когда вы используете имя листа в качестве параметра для его динамического извлечения и возврата результата, вы нарушаете правило кэширования.

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

Я использую фиктивную переменную в функции, эта переменная ссылается на ячейку в электронной таблице, тогда у вас есть Myfunction() в сценарии, который записывает число Math.Ramdon в этой ячейке. Эта "MyFunction" находится в службе триггеров ("Триггеры редактирования / текущего проекта"), и вы можете выбрать разные триггеры событий, например, "Открыто" или "По времени", там вы можете выбрать, например, период времени, от 1 минуты до месяца.

Используйте в качестве параметра финансовую функцию Google. Like =GOOGLEFINANCE("ВАЛЮТА: КАДАРЫ")

Эти функции принудительно перезагружаются каждые x минут

Поскольку скрипт приложения Google является расширением JS, функции должны иметь возможность обрабатывать больше аргументов, чем определено в сигнатуре функции, или меньше. Итак, если у вас есть такая функция, как

function ADD(a, b) {
  return CONSTANTS!$A$1 + a + b
}

тогда вы бы назвали эту функцию как

=ADD(A1, B1, $A$2)

где $A$2 - это какой-то флажок (вставить -> флажок), который вы можете щелкнуть, чтобы "обновить" после того, как вам нужно изменить значение из листа и ячейки КОНСТАНТЫ $ A $1

Другое решение проблемы кеширования.

есть фиктивная переменная в вашем методе. проходить

Filter(<the cell or cell range>,1=1)

в качестве значения этого параметра.

например

=getValueScript("B1","B4:Z10", filter(B4:Z10,1=1))

выход фильтра не используется. однако это указывает на электронную таблицу, что эта формула чувствительна к диапазону B4:Z10.

У меня была похожая проблема при создании панели инструментов для работы. Приведенное выше решение Чамиля (а именно использование функции фильтра Шита, передаваемой в качестве значения фиктивной переменной в вашей функции) работает отлично, несмотря на недавний комментарий от Арсена. В моем случае я использовал функцию для отслеживания диапазона и не мог использовать фильтр в том же диапазоне, так как он создал круговую ссылку. Так что у меня просто была ячейка (в моем случае E45 в приведенном ниже коде), в которой я менял номер каждый раз, когда хотел обновить свою функцию:

=myFunction("E3:E43","D44",filter(E45,1=1))

Как указал Чамиль, фильтр не используется в скрипте:

function myFunction(range, colorRef, dummy) {
  variable 'dummy' not used in code here
}

Учитывая эту особенность, объясненную Henrique Abreu, вы можете попробовать готовую функцию электронных таблиц QUERY, этот SQL-запрос, которым я часто пользуюсь при работе с необработанными данными, и получать данные в виде сводки на другой вкладке, данные результатов обновляются в режиме реального времени после изменения необработанных данных.

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

Что касается функции кэширования, упомянутой Энрике Абреу (у меня недостаточно репутации, чтобы комментировать прямо под его ответом), я провел тестирование и обнаружил, что:

  1. выглядит, что кеш не работает, скрипт функции тестирования показан ниже:

    функция сумматора (база) { Utilities.sleep(5000); возврат базы + 10; }

применив эту пользовательскую функцию adder() к листу, вызвав ячейку, а затем изменив значение этой ячейки вперед и назад, каждый раз, когда я вижу сообщение о загрузке и общее время более 5 секунд. Это может быть связано с обновлением, упомянутым в этой проблеме GAS:

Эта проблема была теперь исправлена. Пользовательские функции в новых листах теперь учитывают контекст и не кешируют значения так агрессивно.

  1. проблема, упомянутая в этой теме, остается, мое тестирование показывает, что лист Google каждый раз пересчитывает пользовательскую функцию ТОЛЬКО КОГДА

    • значение ПРЯМО, вызванное функцией, изменено.

    function getCellValue (sheetName, row, col) {var ss = SpreadsheetApp.getActiveSpreadsheet (); var sh = ss.getSheetByName (sheetName); return sh.getRange (row, col).getValue (); }

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

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

Как сказал @Brionius, добавьте дополнительный динамический аргумент в функцию. если вы используете now(), у вас могут быть проблемы с тайм-аутом, что делает обновление немного медленнее...

cell A1 = int(now()*1000)
cell A2 = function(args..., A1)

Что вы можете сделать, это установить другую ячейку в электронной таблице, которая будет обновляться каждый раз при добавлении нового листа. Убедитесь, что он не обновляется для каждого изменения, а только тогда, когда вы хотите выполнить расчет (в вашем случае, когда вы добавляете лист). Затем вы передаете ссылку на эту ячейку своей пользовательской функции. Как уже упоминалось, пользовательская функция может игнорировать этот параметр.

Я не хотел иметь фиктивный параметр. YMMV на этом.

1 Ячейка, представляющая собой "Список элементов", одна из которых "Обновить"

2 Сценарий с "onEdit", если ячейка "Обновить":

а) Очистить кеш документов

б) Заполнить кэш документов внешними данными (таблица в моем случае)

c) Для всех ячеек с моей пользовательской функцией getStockoData(...)

  • получить формулу

  • установить '=0'

  • установить офулу

г) Установите ячейку в (1) со значением "Готово"

Это обновляет биты, которые вы хотите, НО НЕ БЫСТРО.

Другие вопросы по тегам