Ответы пользователя по тегу Google Sheets
  • Как составить формулу для суммирования столбца над ячейкой?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Sheets
    Учитель, автоэлектрик, программист, музыкант
    Вот так:
    =СУММ(ДВССЫЛ("R2C[0]:R[-1]C";0))
    Ответ написан
    Комментировать
  • Как получить емэил, вносящего изменения в гугл таблицу?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Sheets
    Учитель, автоэлектрик, программист, музыкант
    Для простых триггеров наподобие onEdit и пользовательских функций недоступен объект user, в этом можно убедиться если сделать такой код:
    function onEdit(e) {
      SpreadsheetApp.getActiveRange().setValue(Utilities.formatString("email: %s",e.user.getEmail() ));
    }

    Но никто не запрещает сделать другую функцию и назначить ей триггер "При изменении" (Изменить - Триггеры текущего проекта - Добавление триггера - onEditTrigger - Основное развертывание - Из таблицы - При редактировании - Сохранить):
    function onEditTrigger(event) {
            var userEmail = event.user.getEmail();                  //Email пользователя
    	//Что-то делаем...
    };
    Ответ написан
  • Возможно использовать значение ячейки как ссылку на другую ячейку?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Sheets
    Учитель, автоэлектрик, программист, музыкант
    Если нужно скопировать значение из C4, то
    =C4
    Если нужно скопировать значение по адресу, который лежит в A1, т.е. из "С4", то
    =ДВССЫЛ(A1)
    или
    =INDIRECT(A1)
    Ответ написан
    1 комментарий
  • Как полностью копировать ячейку с одного листа на другой?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Sheets
    Учитель, автоэлектрик, программист, музыкант
    Я бы сделал так:
    /**
     * Копирует значения и форматирование из fromRange в toRange
     *
     * @param {"A1:B10"} fromRange Исходный массив
     * @param {"D1:E10"} toRange Конечный массив
     * @return 0 если выполнилось без ошибок, или описание ошибки
     * @customfunction
     */
    function copyRange(fromRange, toRange){
      var ss = SpreadsheetApp.getActiveSpreadsheet();
      try{
        var source = ss.getRange(fromRange);
        var dest   = ss.getRange(toRange);
        
        dest.setValues(source.getValues());
        dest.setBackgrounds(source.getBackgrounds());
        // и т.д. Есть много чего из форматирования, получается по get... ставится по set...
        
        return 0;//Завершение без ошибок
      }catch(err){
        Logger.log(Utilities.formatString((arguments.callee.toString().match(/function ([^(]*)\(/)[1]) + "(%s) - %s", Array.from(arguments).join(", "), err.message)); //Ошибку в лог
        return err.message;//Завершение с ошибкой
      };
    };

    Использовать так:
    function syncRanges(){
      copyRange("b7:b11", "c7:c11"); // b7:b11 >> c7:c11
      copyRange("f1:f20", "g1:g20"); // f1:f20 >> g1:g20
      //и т.п. можно вызывать несколько раз для разных диапазонов
    };

    И настроить для функции syncRanges() триггер "на изменение таблицы" или "по времени".
    Ответ написан
    Комментировать
  • Как использовать один проект Apps Script для 2х и более Таблиц?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Apps Script
    Учитель, автоэлектрик, программист, музыкант
    Вместо обычного
    var ss = SpreadsheetApp.getActiveSpreadsheet();  //Текущая таблица

    используйте один из вариантов
    var ss = SpreadsheetApp.openById(id); //открытие сторонней таблицы по id
    //или
    var ss = SpreadsheetApp.openByUrl(url);//открытие сторонней таблицы по url

    И потом работайте с ss как с обычной таблицей
    Ответ написан
    1 комментарий
  • Как настроить градиент для графика сна в Google Sheets?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Sheets
    Учитель, автоэлектрик, программист, музыкант
    1) Выделить ячейки
    2) Формат - Условное форматирование
    3) Выбрать "Своя формула"
    4)=И(ДВССЫЛ("RC";0)<>"";ДВССЫЛ("RC";0)>=(0/24);ДВССЫЛ("RC";0)<(5/24))
    5) Установить форматирование для этого диапазона (0-5 часов)
    6) Повторить 2) - 5) для остальных диапазонов
    Демонстрационная таблица
    Ответ написан
    Комментировать
  • Как сделать автозаполнение скриптом?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Apps Script
    Учитель, автоэлектрик, программист, музыкант
    Многое можно сделать чисто формулами. Вот пример - если что-то есть в столбце A, то получается сумма (A + B). Запишите это в C1 и добавьте в A и B значения.
    =arrayFormula(
      еслиошибка(
         если(a:a<>""; a:a+b:b; "")
      )
    )


    Демонстрационная таблица
    Ответ написан
    Комментировать
  • Google Sheets Как ограничить триггер onEdit?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Sheets
    Учитель, автоэлектрик, программист, музыкант
    В параметре e много полезного. Как раз по нему можно ограничить действие скрипта на какие-то листы или отдельные ячейки или по более сложным условиям.
    function onEdit(event) {
    	//Возникает при изменении ячейки
    	var ss = event.source.getActiveSheet();//Текущий лист
      	var address = event.range.getA1Notation().toUpperCase();//Адрес ячейки
    	var row = event.range.getRow();							//Номер строки
    	var col = event.range.getColumn();						//Номер столбца
    	var newValue = event.value;								//Новое значение
    	var oldValue = event.oldValue;							//Старое значение
    	
      if (["Лист1","Лист2"].indexOf(ss.getName())==-1) return;	//Указываем на каких листах должен работать скрипт
    	
    	//Что-то делаем...
      };
    Ответ написан
    Комментировать
  • Как в Гугл таблицах разбить текст по жирности?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Sheets
    Учитель, автоэлектрик, программист, музыкант
    Нужно использовать скрипт, в нём смотреть getRichTextValue()

    /**
     * Аналог функции split. Разбивает по наличию жирности у текста
     * [ ProgrammerForever (c) 2020 ]
     * @param {"A1"} rangeName Имя ячейки
     * @return Возвращает массив строк с чередующейся жирностью
     * @customfunction
     */
    function splitByBold(rangeName) { 
      if (!rangeName) {
        throw "Параметр rangeName не задан. Должен быть адресом ячейки"
      };
      
      var rtv = SpreadsheetApp.getActiveSheet().getRange(rangeName).getRichTextValue();
      
      if (rtv) {
        rtv=rtv.getRuns()
      }else{
        return SpreadsheetApp.getActiveRange().getValue();
      };  
      
      var outData = [rtv[0].getText()];
      var isBold = rtv[0].getTextStyle().isBold();
      var k=0;
      for (var i = 1; i < rtv.length; i++){
        if (rtv[i].getTextStyle().isBold() === isBold){
          outData[k]+= rtv[i].getText();
        }else{
          k+=1;
          outData[k]= rtv[i].getText();
          isBold = rtv[i].getTextStyle().isBold();
        };
      };
      return outData;
    }

    Демонстрационная таблица
    Ответ написан
    Комментировать
  • Google таблицы, заполнение одного листа инфой из другого?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Sheets
    Учитель, автоэлектрик, программист, музыкант
    Всё просто. Берем столбец с клиентами
    A:A
    Берем столбец со статусами
    B:B
    Заменяем клиентов на пустые значения, если договора нет, используем "массовую" формулу ArrayFormula()
    ArrayFormula(ЕСЛИ(B:B="Заключен";A:A;""))
    Что получилось - разворачиваем на 90 градусов функцией ТРАНСП()
    =ТРАНСП(ArrayFormula(ЕСЛИ(B:B="Заключен";A:A;"")))
    Можно изначально отфильтровать пустые строки, тогда получится так:
    Таблица демонстрационная
    Финт с превращением в пустые значения нужен чтобы данные не съехали, если изменится статус у клиентов.
    Ответ написан
    Комментировать
  • Как можно выводить изменения ячейки в гугл таблицах?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Sheets
    Учитель, автоэлектрик, программист, музыкант
    Нужно отслеживать событие onEdit(event) и писать лог в нужный лист.
    function onEdit(event) {
      //Возникает при изменении ячейки
      var ss = event.source.getActiveSheet();//Текущий лист
      var address = event.range.getA1Notation().toUpperCase();//Адрес ячейки
      var row = event.range.getRow();      //Номер строки
      var col = event.range.getColumn();  //Номер столбца
      var newValue = event.value;            //Новое значение
      var oldValue = event.oldValue;        //Старое значение
      
      if (["Лист1","Лист2"].indexOf(ss.getName())==-1) return;	//Указываем на каких листах должен работать скрипт
      //Можно при желании ещё фильтровать по строке/столбцу (row/col), или по старому/новому значению (oldValue/newValue)
      
      var archive = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Архив");
    
      archive.getRange(archive.getLastRow()+1, 1).setValue(
        formatDateTime(new Date())+" " + "[" + ss.getName() + "!" + address + "] '" + (oldValue==undefined?"":oldValue) + "' >> '" + (newValue==undefined?"":newValue) +"'"
      );
    };
    
    function formatDateTime(date) {
    
      var dd = date.getDate();
      if (dd < 10) dd = '0' + dd;
      var mm = date.getMonth() + 1;
      if (mm < 10) mm = '0' + mm;
      var yy = date.getFullYear() % 100;
      if (yy < 10) yy = '0' + yy;
      
      var hh = date.getHours();
      if (hh < 10) hh = '0' + hh;
      var MM = date.getMinutes();
      if (MM < 10) MM = '0' + MM;
      var ss = date.getSeconds();
      if (ss < 10) ss = '0' + ss;
      
      return dd + '.' + mm + '.' + yy + ' ' + hh + ':'+ MM + ':'+ ss;
    }

    Вот ссылка на демо
    Ответ написан
    4 комментария
  • Как перенести данные из google forms в google sheets?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Sheets
    Учитель, автоэлектрик, программист, музыкант
    Это должно помочь. На строки в ДВССЫЛ() все трюки с автозаменами не распространяются.
    =arrayformula(ДВССЫЛ("'Ответы на форму (1)'!c1:c)"))
    Ответ написан
    Комментировать
  • Как отобразить только последний успешный результат IMPORTXML и игнорировать, если возвращается ошибка?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Sheets
    Учитель, автоэлектрик, программист, музыкант
    Тут только скрипт поможет. Складировать результаты запросов (дата или номер + данные) в отдельный диапазон скриптом (определить последнюю незаполненную строку, положить данные по таймеру), и оттуда брать последний по дате без ошибок функцией FILTER().
    Ответ написан
    Комментировать
  • Как получить СУММЕСЛИ только видимых ячеек?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Sheets
    Учитель, автоэлектрик, программист, музыкант
    Не совсем то, но думаю что поможет. Используейте FILTER(Диапазон;Условие1;Условие2;...УсловиеN) для подсчёта суммы.
    например, в вашем случае, в B47 пишем:
    =СУММ(FILTER($C$2:$C$45;$B$2:$B$45=A47))
    Где A47 - фильтр-условие на диаметр трубопровода
    А ещё лучше - сразу сделать так:
    =ЕСЛИОШИБКА(СУММ(FILTER($C$2:$C$45;$B$2:$B$45=A47));0)
    Ответ написан
    Комментировать
  • Как скопировать значение из ячейки, google sheets?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Sheets
    Учитель, автоэлектрик, программист, музыкант
    Если нужно зафиксировать курс на какой-то дате, используйте функцию GOOGLEFINANCE(код; [атрибут]; [дата_начала]; [дата_окончания|количество_дней]; [интервал])
    Информация о функции на русском
    Например, в A1 пишите так (вместо USD и RUB можно подставить любые другие валюты):
    =GoogleFinance("CURRENCY:USDRUB"; "close"; D2)
    В D2 пишите дату закупки. И курс валюты подтягивается с определенной даты. Т.к. это исторические данные, то они уже не поменяются.
    Ответ написан
  • Существует ли возможность связать GoogleSheets без improtrange?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Sheets
    Учитель, автоэлектрик, программист, музыкант
    Заверните IMPORTRANGE в FILTER(Данные;Условие1;Условие2...) по условию. Или попробуйте обработать скриптом данные.
    Вот такая штука может пригодиться(чтобы выбрать первые rows строк из данных), как-то сделал и теперь постоянно пользуюсь:
    /**
     * Возвращает rows строк и cols столбцов из array
     *
     * @param {A:A} array Исходный массив
     * @param {10} rows Количество строк. По умолчанию возвращаются все строки
     * @param {1} cols Количество столбцов. По умолчанию возвращаются все столбцы
     * @return Возвращает rows строк и cols столбцов из array
     * @customfunction
     */
    function take(array,rows,cols) {
      if (!array.map) {return array};
      var rows = rows||array.length;
      var cols = cols||array[0].length;
      
      if (array.length>rows) {array.length = rows};
      return array.map(
        function(row){
          return row.map?((row.length>cols)?row.splice(cols,row.length-cols):row):row;
        }
      );
    }
    Ответ написан
  • Как дописать скрипт Google Apps script?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Apps Script
    Учитель, автоэлектрик, программист, музыкант
    Получать данные по одной ячейке - это ооооооочень долго. Лучше взять все данные сразу в нужном диапазоне, например так:
    var data = ss.getActiveSheet().getRange("A3:A1000").getValues();

    И потом можно обращаться к этим данным по номеру строки и номеру столбца, не забывая что отсчёт идёт с нуля:
    data[row][column]
    Записывать тоже нужно массово. В итоге получится что-то такое:
    function onOpen() { 
      //Выполняется при открытии
      SpreadsheetApp
      .getUi()
      .createMenu('Меню')
      .addItem('Выполнить','doIt')
      .addToUi();
    };
    
    function doIt() {
      try{
        var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); //Текущий лист
        
        var data1 = ss.getRange("A3:E" + ss.getMaxRows()).getValues();
        var data2 = ss
        .getRange("m4:n" + ss.getMaxRows())
        .getValues()
        .filter(function(row) // Убираем пустые строки
                {
                  return row[0]!="";
                }
               );
        
        for (var row2=0;row2<data2.length;row2++){
          for (var row1=0;row1<data1.length;row1++){
            if (data1[row1][0]===data2[row2][0]){
              data1[row1][4]+=data2[row2][1];
              break; //Если значение найдено, дальше не ищем
            };
          };
        };
        
        ss.getRange("A3:E" + ss.getMaxRows()).setValues(data1); //Вывод данных
        SpreadsheetApp.getActive().toast("Готово!");
      }catch(e){ //Если вдруг ошибка
        Logger.log("Ошибка! " + e);
      };
    }

    Демо-таблица
    Ответ написан
    6 комментариев
  • Как сравнить два числа в одной ячейке в Google Таблицы?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Sheets
    Учитель, автоэлектрик, программист, музыкант
    Используйте REGEXEXTRACT(текст;регулярка) для извлечения кусков текста, чтобы потом сравнить, например что первое меньше второго
    =REGEXEXTRACT(A1;"(\d)+\:") < REGEXEXTRACT(A1;"\:(\d)+")

    Чтобы подсветить соседнюю ячейку, можно использовать Формат - Условное форматирование
    Ответ написан
    1 комментарий
  • Как избавиться от Loading?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Apps Script
    Учитель, автоэлектрик, программист, музыкант
    Если данные сконцентрированы в каком-то месте, можно вместо пользовательской функции использовать просто функцию. Только добавить получение из таблицы аргументов, и вывод результата. Обновление можно повесить на открытие таблицы, на onEdit(event) или на триггер по времени, как нравится. Но такой способ менее информативный, на самом деле. Непонятно обновилось оно или нет. Обычно я в конце таких функций(если нет возможности сделать пользовательскую функцию) добавляю тост о том, что всё завершено.
    SpreadsheetApp.getActive().toast("Функция завершена");
    Ответ написан
    Комментировать
  • Как сделать очистку ячеек выбранного диапазона при активации другой?

    ProgrammerForever
    @ProgrammerForever Куратор тега Google Apps Script
    Учитель, автоэлектрик, программист, музыкант
    Что значит "активная"? Нет события "активная ячейка" но есть событие "ячейка изменилась" - onEdit(event)
    Вот заготовка кода для этой функции:
    function onEdit(event) {
    	//Возникает при изменении ячейки
    	var ss = event.source.getActiveSheet();//Текущий лист
      	var address = event.range.getA1Notation().toUpperCase();//Адрес ячейки
    	var row = event.range.getRow();							//Номер строки
    	var col = event.range.getColumn();						//Номер столбца
    	var newValue = event.value;								//Новое значение
    	var oldValue = event.oldValue;							//Старое значение
    	
      if (["Лист1","Лист2"].indexOf(ss.getName())==-1) return;	//Указываем на каких листах должен работать скрипт
    	
    	//Что-то делаем...
      };

    Вместо "Что-то делаем" впишите нужные действия, например, очистку диапазона. Код для очистки можно сделать макрорекордером Инструменты - Макросы - Записать макрос
    1) Запись
    2) Выделить диапазон
    3) Del
    4) Стоп записи
    Или использовать такой код:
    SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Лист1").getRange("A2:B28").clear();

    Но тут есть момент - эта очистка на том же листе может снова спровоцировать onEdit() и надо с этим бороться, проверяя какой диапазон меняется перед тем как что-то очистить
    if (address !="B2") return;
    Ответ написан
    Комментировать