Задать вопрос
  • Возможно ли в Google Sheets каким-либо образом фиксировать дату изменения значения ячейки?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Формулы не могут сохранить состояние ячейки, поэтому необходимо использовать скрипты.
    Общий код выглядит так

    function myFunction(e) {
    
      try {
        if (!e || !e.range) return;
        if (e.range.columnStart > 1) {
          var targetCell = SpreadsheetApp.getActiveSheet()
            .getRange(e.range.rowStart, 1, e.range.rowEnd - e.range.rowStart + 1);
    
          /* if you want insert the date once uncomment the row below
          *
          **/
          // if(!targetCell.getValue())
          targetCell.setValue(new Date());
          
        }
      } catch (err) {
        SpreadsheetApp.getActiveSpreadsheet().toast(err.message, 'Error!!1');
      }
    }


    Пример для тестирование и объяснение можно посмотреть тут https://gist.github.com/contributorpw/b179e819c0ee...
    Ответ написан
  • Что делать, если случайно удалил файл с расширением xlsx.gsheet?

    oshliaer
    @oshliaer
    Google Products Expert
    Ваша последняя сихронизированная копия еще какое-то время находится на серверах Google - все не удаляется мгновенно. Попробуйте восстановить файлы с этой инструкцией https://gdriveru.blogspot.com/2017/05/restorefiles.html Промахов еще не было, а количество восстановлений давно перестали считать.
    Ответ написан
    Комментировать
  • Google forms POST или api?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Единственный на данный момент "правильный" способ управления Формами - использование Google Apps Script. Для реализации API используйте специальный триггер `doGet`.

    У вас должно получиться что-то вроде этого

    function doGet(e){
      /* если `e` содержит параметр на отключение Формы */
      form.setAcceptingResponses(false);
      /* если `e` содержит параметр на разрешение Формы принимать ответы */
      form.setAcceptingResponses(true);
    }


    Опубликуйте скрипт как веб приложение и дергайте из питона сколько лезет. Если сильно заморочиться, то можно опубликовать как API и контролировать доступ к скрипту на уровне авторизации пользователя.
    Ответ написан
    Комментировать
  • Сбор названий таблиц в папке в одну общую таблицу?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Да, этот вопрос можно решить несколькими путями.

    Например, можно отслеживать состояие папки. Или отслеживать состояние Диска пользователя. Выбор будет зависеть от вашего бизнес процесса.

    Это можно сделать на любом языке программирования, который умеет работать с HTTP. Можно реализовать на скриптах Google Apps Script.
    Ответ написан
    Комментировать
  • Как экспортировать гугл таблицу в rss?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Вы должны обуликовать скрип от своего имени для всех в Интернете, тогда ридер будет подхватывать данные, отправляемые HtmlService.

    Если вы генерируете RSS в шаблон HtmlService, то

    function doGet() {
      return ContentService.createTextOutput(HtmlService.createTemplateFromFile("rss").evaluate().getContent())
              .setMimeType(ContentService.MimeType.RSS);
    }


    Или же вы можете создавать полноценный документ используя XmlService

    function doGet() {
      var xml = XmlService.getPrettyFormat().format(document);
      return ContentService.createTextOutput(xml)
              .setMimeType(ContentService.MimeType.RSS);
    }
    Ответ написан
    Комментировать
  • Как производить округления в запросе QUERY?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Google Query Language не поддерживает директиву округления.

    5c5a958660d93221607154.png

    Вы можете использовать округление форматированием, которое решает вопрос отображения

    =QUERY({A2:A6,A2:C6},"select Col1, Col2 format Col1'', Col2'#.00'")


    или предварительное округление, которое может внести некоторые неточности в результирующие данные

    =QUERY({A2:A6,ARRAYFORMULA(ROUND(A2:A6,2))},"select Col1, Col2")


    Пример Таблицы https://docs.google.com/spreadsheets/d/1NfP4x3S_EU...
    Ответ написан
  • Как написать макрос, который активирует другой макрос, в зависимости от условия?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Можно использовать инструкцию switch

    function oneButtonMacros() {
      switch (SpreadsheetApp.getRange('Sheet1!A1').getValue()) {
        case 1:
          macros1();
          break;
        case 2:
          macros2();
          break;
        case 3:
          macros3();
          break;
      }
    }
    Ответ написан
    1 комментарий
  • Как добавить в текущую дата google form?

    oshliaer
    @oshliaer
    Google Products Expert
    Формы сами по себе хранят данные называемые "Отметка времени", в которых указывается последняя дата изменения ответа Формы.

    Если выгрузить эти ответы в Таблицу, то эти данные всегда идут первой ячейкой. В самой же Форме их можно получить либо в интерфейсе ответов, либо программно через Google Apps Script.
    Ответ написан
    Комментировать
  • Как сравнить два диапазона и выбрать нужные данные?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Вам необходимо строить индекс по принципу баз данных, иначе в циклах все будет очень сложно.

    function main() {
      var dataSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(
        'данные'
      );
      var dataArray = dataSheet.getDataRange().getValues();
      var listSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(
        'список сайтов'
      );
      var listArray = listSheet.getDataRange().getValues();
      // Строим индекс
      var listIndex = listArray.map(function(r){
        return r[0];
      });
      for (var j = 1; j < dataArray.length; j++) {
        if(dataArray[j][0] === '') continue;
        var pos = listIndex.indexOf(dataArray[j][0]);
        if (pos >= 0) {
          // Обновляем
          listSheet.getRange(pos + 1, dataArray[j].length + 1).setValue(new Date());
        } else {
          // Добавляем
          listSheet.appendRow([].concat(dataArray[j], new Date()));
        }
      }
    }
    Ответ написан
    Комментировать
  • Как сделать взаимосвязь ячеек на разных листах в гугл-таблицах?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Да, такое возможно.

    Вам необходимо использовать Google Apps Script или другой язык программирования для реализации поставленной задачи. Постарайтесь изначально продумать пути решения, чтобы потом не запутаться в дебрях наполовину реализованных идей.

    Возможные пути и некоторые вопросы:

    • Обновление данных массивом периодически / по расписанию
    • Обновление данных по событию. Например, пользователь открыл Таблицу / внес изменения
    • Обновление только части данных
    • Мутация данных в момент переноса
    • Определение роли пользователя / менеджера данных
    • Другие ограничения прав доступа / выполнения кода


    Если вам нужен конкретный пример или кусок кода, то оформите пост дополнительной информацией согласно правилам. Например, как тут Google Apps Script для Google таблиц: как переимен...
    Ответ написан
    2 комментария
  • Google Apps Script для Google таблиц: как переименовать все листы в таблице скриптом?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Вам просто необходимо получить листы Таблицы, и переименовать их как надо.

    Решение

    SpreadsheetApp.openById('blah-blah')
      .getSheets()
      .forEach(function(sheet) {
        var name = sheet.getRange('J2').getValue();
        if (name)
          try {
            sheet.setName(name);
          } catch (error) {
            console.error('CATCHED', error);
          }
      });


    Как делают

    Основная идея заключается в том, чтобы перебрать все элементы массива, отсортировать лишнее, а с выбранными элементаи произвести действие. Функция userActionRenameSheets демонстрирует это.

    /* exported userActionRenameSheets */
    
    /**
     * Действие пользователя или триггера. Внешний вызов без параметров
     */
    function userActionRenameSheets() {
      var spreadsheet = SpreadsheetApp.openById('blah-blah');
    
      /** @type {filterSheets} */
      var filterSheets = function(sheet) {
        return true;
      };
    
      /** @type {renameRule} */
      var renameRule = function(sheet) {
        var name = sheet.getRange('J2').getValue();
        if (name)
          try {
            sheet.setName(name);
          } catch (error) {
            console.error('CATCHED', error);
          }
        return sheet;
      };
    
      var sheets = renameSheetsByCellValue_(spreadsheet, filterSheets, renameRule);
      // Делать что-нибудь дальше
    }
    
    /**
     * Переименовывает листы в Таблице согласно заданным правилам
     *
     * @param {GoogleAppsScript.Spreadsheet.Spreadsheet} spreadsheet Таблица,
     *         в которой производим переименование
     * @param {filterSheets} Фильтр листов на всякий случай, вдруг что-то надо да пропустить
     * @param {renameRule} Правило переименования, может возвращать что угодно
     * @param {any[]} Массив отфильрованных результатов функции renameRule
     */
    function renameSheetsByCellValue_(spreadsheet, filterSheets, renameRule) {
      var res;
      var sheets = spreadsheet.getSheets();
      if (filterSheets) res = sheets.filter(filterSheets) || sheets;
      if (renameRule) res = res.map(renameRule);
      return res;
    }
    
    /**
     * Фильтр листов
     * @callback filterSheets
     * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet Текущий лист
     * @param {number} index Текущий индекс массива
     * @param {GoogleAppsScript.Spreadsheet.Sheet[]} sheets Текущий массив
     * @returns {boolean}
     */
    
    /**
     * Правило переименования
     * @callback renameRule
     * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet Текущий лист
     * @param {number} index Текущий индекс массива
     * @param {GoogleAppsScript.Spreadsheet.Sheet[]} sheets Текущий массив
     * @returns {any}
     */
    Ответ написан
  • Как получить примечания (Notes) из Google Sheet, используя Python?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    from googleapiclient.discovery import build
    service = build('sheets', 'v4')
    
    response = service.spreadsheets().get(spreadsheetId = spreadsheetId,
        fields = 'sheets(data.rowData.values.note)').execute()
    
    print(response)


    Запустить код "здесь и сейчас" можно по ссылке https://colab.research.google.com/drive/1dbUChgxPF...
    Ответ написан
    Комментировать
  • Как добавить колонку Google Sheet в определённое место (Python, gspread)?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Используйте базовый API

    sht = gc.open_by_key(spreadsheetId)
    
    requests = []
    
    requests.append({
          "insertDimension": {
            "range": {
              "sheetId": sheetId,
              "dimension": "COLUMNS",
              "startIndex": 2,
              "endIndex": 4
            },
            "inheritFromBefore": True
          }
        })
    
    body = {
        'requests': requests
    }
    
    sht.batch_update(body)


    Запустить код "здесь и сейчас" можно по ссылке https://colab.research.google.com/drive/1IWmX5xuOE...

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

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Наверное, gspread является неплохим решением, но с появлением Sheets API v4, все стало немного проще.

    spreadsheetId=''
    new_sheet_title=''
    
    from googleapiclient.discovery import build
    service = build('sheets', 'v4')
    
    requests = []
    
    requests.append({
        'addSheet': {
            'properties': {
                'title': new_sheet_title
            }
        }
    })
    
    body = {
        'requests': requests
    }
    
    response = service.spreadsheets().batchUpdate(
      spreadsheetId=spreadsheetId,
      body=body).execute()


    Запустить код "здесь и сейчас" можно по ссылке https://colab.research.google.com/drive/1_IdQAxqk7...
    Ответ написан
    Комментировать
  • Реально ли на уровне dns сервера сослаться на файл на чужом хосте?

    oshliaer
    @oshliaer
    Google Products Expert
    Я думаю, что овчинка выделки не стоит.

    Прежде существовала такая функция, как Google Drive Host, которая автоматически хостила любой контент в публичной папке. Соответственно, заголовки они отдавали правильные, и браузер делал правильные вещи.

    Сейчас эта функция отключена, и сервер отдает уже другой Content-Disposition.

    Плюс, без ID соседнего файла вы не сможете подтянуть внешние файлы, даже если вам удастся подменить заголовки.
    Ответ написан
  • Как отключить обновление ячеек в гугл таблицах?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Я думаю, что в данном случае, если вам не нужно постоянно обновлять данные, лучше воспользоваться скриптом, который сможет реализовать подобный функционал.
    Ответ написан
    Комментировать
  • Как отключить автозаполнения полей в гугл таблицах?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Формула работает корректно - она находит все элементы удовлетворяющие условию. Вам необходимо получать только первый элемент массива. Например, вот так

    =IMPORTXML(
        "http://shop.marlin.com.ua/products/gidrokostyum-marlin-skiff-20-7-mm";
        "(//div[@class='mainTool']//p[1]//span[@class='prices'])[1]"
    )


    Рабочий пример https://docs.google.com/spreadsheets/d/1FH3QTXRRKH...
    Ответ написан
    Комментировать
  • Обратный отсчет в таблицах Google?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    5c48becdc4b69920432936.png

    Необходимы вводные параметры:
    1. Само число
    2. Дата, с которой начинать отсчет


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

    =B1+INT(B2)-INT((TODAY())), где В1 - заданное число, В2 - начальная дата.
    Тоже самое, но без приведения типов
    =B1+B2-TODAY()

    или одной формулой

    =8+INT(DATE(2019;1;21))-INT((TODAY())), 8 - заданное число, DATE(2019;1;21) - начальная дата
    Тоже самое, но без приведения типов
    =8+DATE(2019;1;21)-TODAY()

    Живой пример
    Ответ написан
    Комментировать
  • Как настроить отправку данных из таблицы в виде одной строки в другую закрытую таблицу?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Действительно, это не так очевидно с первого раза, но, когда сталкиваешься, то понимаешь, что пользователь должен быть редактором, чтобы вносить изменения. Чтобы решить эту задачу необходимо предоставить другой интерфейс для ввода данных.

    Замените myFunction на что-то вроде:
    function recordToMain(){
      // Берет диапазон 'Источник!B4:B8' активной Таблицы, т.о. это встроенный скрипт
      var data = SpreadsheetApp.getActive().getRange('Источник!B4:B8')
      .getValues().map(function(row){return row[0];});
      var url = 'https://script.google.com/macros/s/ZZZ/exec';
      var options = {
        method: 'POST',
        headers: {
          ContentType: 'application/json'
        },
        payload: JSON.stringify(data),
        muteHttpExceptions: true
      };
      UrlFetchApp.fetch(url, options); 
    };


    Так же создайте новый проект скриптов, в котором создайте функцию вроде:
    function doPost(e) {
      SpreadsheetApp.openById('YYY') // Должна существовать
      .getSheetByName('Приемник')    // Должен быть лист 'Приемник'
      .appendRow([new Date()].concat(JSON.parse(e.postData.contents)));
    }

    Когда вы опубликуете новый проект для всех от имени себя, то получите url_master для первой функции.
    Ответ написан