Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I force a recalculation of cell using ImportRange function in a Google Spreadsheet?

I have a spreadsheet Target that uses ImportRange to get some data from another spreadsheet Source, as in

A6 = query(ImportRange("mykey", "Weekly!B:BI"), CONCATENATE("select * WHERE Col1='",B3,"'"), 0)

The select clause is to sub-select the data that matches on a value in B3 - if this cell value is changed then the import is updated "immediately".

I want to be able to force an update if someone changes something in the Source spreadsheet so that we see it reflected in the Target "immediately". Currently this only happens "after some unspecified time" which is up to a minute or so, and too slow for my purposes.

Update:

As per the answer and comments below, I added a function UpdateTarget in the Source that is called from a on edit trigger*:

function UpdateTarget() {
  try {
    var ss = SpreadsheetApp.openById("targetID");
  }
  catch(err)
  {
    Browser.msgBox(err);
  }
  var sheet = ss.getSheetByName("Weekly");
  sheet.getRange("A4").setValue("=query(ImportRange("sourceID", "Weekly!B:BI"), CONCATENATE("select * WHERE Col1='",B3,"'"), 0) ");
  SpreadsheetApp.flush();
}

This seems to work more effectively but I may as well have a script to write the updated values directly into the target if I'm going down this route.

I really wanted the Target to be a template which other users could duplicate and which would extract specific "live" data from a master Source, I am reluctant to implement scripts in the Source that would need maintaining as new Targets are added.

I think what I really need is a way of re-stating the formula such that it depends on a cell which can be edited and will trigger a re-calc - but the has no effect on the result?

(*An aside: I found that the openByID function returned "Action not allowed" exception unless its called via an explicit trigger - onEdit is forbidden from editing other spreadsheets -see https://developers.google.com/apps-script/understanding_triggers).

like image 559
BobC Avatar asked Oct 06 '22 19:10

BobC


2 Answers

Formulas are recalculated when the spreadsheet is opened by a user or when a cell (within the same spreadsheet) is changed that affects the formula.

Since you are working with two different spreadsheets, the latter case is not applicable.

From which spreadsheet are you calling the flush() function. I assume it is in the target spreadsheet. This will be of no use.

One solution would be to write a script in the source spreadsheet that will modify the target spreadsheet each time the source is edited

like image 165
Srik Avatar answered Oct 08 '22 09:10

Srik


Force recalculation of importrange by reinstating the cell formula

Required:

Imported Data - Your target where everything will be copied to.

Imported Data Config - Has the following fields:

+---------------------------------------------+--------------------------------+
|                      A                      |               B                |
+---------------------------------------------+--------------------------------+
| Import Data from Spreadsheet with the key:  | key                            |
| Import Data from Spreadsheet between range: | A:AA                           |
| Imported Data select columns:               | SELECT *                       |
| Imported Data criteria:                     | WHERE Col15 contains 'Offered' |
| Imported Data should by ordered by column:  | ORDER BY Col1                  |
+---------------------------------------------+--------------------------------+

Script:

function onOpen() {
try {
var ss = SpreadsheetApp.getActiveSpreadsheet();
}
catch(err)
{
Browser.msgBox(err);
}

var configsheet = ss.getSheetByName("Imported Data Config");

var configkey = configsheet.getRange("B1").getValue();
var configrange = configsheet.getRange("B2").getValue();
var configselect = configsheet.getRange("B3").getValue();
var configwhere = configsheet.getRange("B4").getValue();
var configorderby = configsheet.getRange("B5").getValue();

var importedsheet = ss.getSheetByName("Imported Data");
importedsheet.getRange("A1").setValue('=QUERY(IMPORTRANGE("' + configkey + '","' + configrange + '"),"' + configselect + ' ' + configwhere + ' ' + configorderby + '")');

SpreadsheetApp.flush();

// Solution of sourcecode is: http://stackoverflow.com/questions/13631584/how-can-i-force-a-recalculation-of-cell-using-importrange-function-in-a-google-s
// OnOpen Trigger: https://developers.google.com/apps-script/understanding_triggers
// Active Spreadsheet solution: https://productforums.google.com/forum/#!topic/docs/XIY0WNX0uL8

Browser.msgBox("Sync Complete!");
}

This allows you to change your formula without editing the script, and make it easier to transfer the script across various sheets.

like image 45
user3254726 Avatar answered Oct 08 '22 09:10

user3254726