Как добавить формулу рядом со скопированным диапазоном данных с помощью Google Apps Script? - PullRequest
0 голосов
/ 15 марта 2019

У меня проблемы с пониманием массивов, но я знаю, что это то, что мне нужно сделать, чтобы решить мою проблему.В настоящее время я копирую необходимые данные с другого листа на вкладку, копирую эту таблицу данных, а затем вставляю ее в другую вкладку на этом листе.Теперь мне нужно добавить еще один столбец в конце этих окончательно созданных данных, который представляет собой формулу в каждой соседней ячейке, то есть столбец AP, начинающийся в AP2.Вот сценарий:

function CopyDataToNewFile() {
  var sss = SpreadsheetApp.openById('some id');
  var ss = sss.getSheetByName('Outcome'); // ss = source sheet
  var destination = SpreadsheetApp.openById('other id');
  var target = destination.getSheetByName('Final');

  ss.copyTo(destination);

  var data = destination.getSheetByName('Copy of Outcome');
  var infoTable = data.getRange(2, 1, data.getLastRow(), data.getLastColumn());
  var lastRow = target.getLastRow();

  infoTable.copyTo(target.getRange(lastRow + 1, 1), {contentsOnly: true});

  destination.setActiveSheet(destination.getSheetByName('Copy of Outcome'));
  destination.deleteActiveSheet();
}

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

'=vlookup($I2, IMPORTRANGE("https://docs.google.com/spreadsheets/d/<yet another id>/edit#gid=1203869430", "Source_Hours!A:B"), 2, false)'

Вот как я пытался это сделать:

 function CopyDataToNewFile() {
      var sss = SpreadsheetApp.openById('some id');
      var ss = sss.getSheetByName('Outcome'); // ss = source sheet
      var destination = SpreadsheetApp.openById('other id');
      var target = destination.getSheetByName('Final');


  ss.copyTo(destination);

  var data = destination.getSheetByName('Copy of Outcome');
  var infoTable = data.getRange(2, 1, data.getLastRow(), data.getLastColumn());
  var lastRow = target.getLastRow();

  infoTable.copyTo(target.getRange(lastRow + 1, 1), {contentsOnly: true});


 target.getRange(2,infoTable.getLastColumn()+1,infoTable.getLastRow(),1).setFormula('=vlookup($I2,IMPORTRANGE("https://docs.google.com/spreadsheets/d/1f7_unFqRkI6O2EHBLsNGLRCH5j9rlEXBdVnRLTgS_lM/edit#gid=1203869430","Source_Hours!A:B"),2,false)');


  destination.setActiveSheet(destination.getSheetByName('Copy of Outcome'));
  destination.deleteActiveSheet();
}

Он работает при первом запуске сценария, но при следующем запуске он не добавляет формулу в последнем столбце.Я не программист, просто знаю достаточно, чтобы быть опасным.:)

1 Ответ

0 голосов
/ 18 марта 2019

Ваше решение было близко. Мой рекомендуемый подход - создать ссылку на первую строку, в которую будет скопирован ваш сценарий - target.getLastRow() + 1, - а затем использовать эту ссылку как для копии с датой, так и для записи формулы. Ваш сценарий также имел возможную проблему в том, что вы предполагали, что имя листа всегда было "Copy of Outcome" - это не является строго гарантированным истинным (рассмотрите возможность копирования листа дважды без удаления первой копии). Вместо этого свяжите возвращаемое значение Sheet#copyTo, поскольку это вновь созданная копия листа. Таким образом, имя скопированного листа не имеет значения - сценарию не нужно, чтобы оно функционировало должным образом.

function CopyDataToNewFile() {
  const source = SpreadsheetApp.openById('some id').getSheetByName('Outcome');
  const destination = SpreadsheetApp.openById('other id');
  const target = destination.getSheetByName('Final');
  if (!source || !target)
    throw new Error("Missing required worksheets (sheet names not found)");

  // Copy the source sheet and get a reference to the copy.
  var datasheet = source.copyTo(destination);
  var infoTable = datasheet.getRange(2, 1, datasheet.getLastRow(), datasheet.getLastColumn());

  // Copy the table contents to the end of the target sheet.
  // Determine the first row we are writing data into.
  const startRow = target.getLastRow() + 1;
  infoTable.copyTo(target.getRange(startRow, 1), {contentsOnly: true});
  // Set a column formula in the adjacent column.
  target.getRange(startRow, 1 + infoTable.getNumColumns(), infoTable.getNumRows(), 1)
    .setFormula("some formula");

  // Remove the intermediate sheet.
  destination.deleteSheet(datasheet);
}

Новые используемые функции:

Альтернативный метод, который использует массивы JavaScript для ограничения количества используемых методов службы электронных таблиц, возможен, поскольку вы, как представляется, хотите только передать значения. Это использует преимущества цепочки, поскольку Range#setValues возвращает ссылку на диапазон, в который был записан. Это предполагает, что значения на исходном листе «Результат» не зависят от рабочей книги. Если в «Результате» есть формулы, которые относятся к другим рабочим листам в той же рабочей книге, то, естественно, это не сработает, поскольку значения будут относиться к исходной рабочей книге, а не к целевой книге.

  ...
  const dataToCopy = source.getDataRange().getValues();
  dataToCopy.shift(); // remove header row.
  const startRow = target.getLastRow() + 1;
  const numRows = dataToCopy.length;
  const numColumns = dataToCopy[0].length;
  target
    .getRange(startRow, 1, numRows, numColumns)
    .setValues(dataToCopy)
    .offset(0, numColumns, numRows, 1) // offset is from the top-right cell of the range
    .setFormula("some formula");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...