5

I have a Google Spreadsheet with about 3000 rows of data (and about 30 columns). The data is laid out in standard fashion with column headers and one row per data item. The data represent case studies and articles used in various academic courses, and the dataset is always growing.

I need to search/query the data based on specified parameters. For example, I'd like to run this query : select * where course_no = 123 and instructor = Smith and year = 2012. I'd like to get a range of data as the result, which I can then either simply display as raw data on a new Sheet, or manipulate into some kind of report using GAS, or perhaps just email raw data to a recipient.

It looks like the Google Visualization API offers nice query options (I'm looking at the setQuery method of the google.visualization.Query class), but is it possible to use this without attaching it to a Chart or visualization? Can I just call it in script and then manage the range it returns myself? When I try this, I get an error "ReferenceError: google is not defined" at this line :

var query = new google.visualization.Query(my_data_source_url);

I'm also not sure that using the spreadsheet url as the data_source_url in the line of code above is the right thing to do, though that's what I'm trying.

I'm trying this because I'm assuming that using this sort of query approach is more efficient than searching through the cells one by one (like is suggested here How do I search Google Spreadsheets?) but I appreciate all feedback. Thank you! Carrie

Community
  • 1
  • 1
Carrie
  • 1,037
  • 2
  • 12
  • 19

2 Answers2

3

Unfortunately it's not currently possible to directly load Google Visualisation API in a Google Apps Script project. You do have a couple of options though:

  1. Use the noSQL storage build into Google Apps Script (ScriptDb) to read the spreadsheet into a database before querying the response.

  2. Forget querying the data in Apps Script and use the QUERY formula in a sheet (this uses the same syntax as the Google Visualization API Query Language

  3. If using old Sheets you can File > Publish to the web and then query the data in your script using the URL Fetch Service and calling the data by Setting the Query in the Data Source URL <- the problem with this way is you've potentially got a lot of work to process the returned data which can be html, csv or json. This simple tool helps you build the datasource url.

Personally, depending on the scenario, I'd try #2 but failing that go with #1

mhawksey
  • 2,013
  • 5
  • 23
  • 61
  • #3 is the only way to go here. #1 doesnt make much sense unless your source changes rarely. Ive done #3 before, its not that hard and will be faster than looping all the data. You need to take care of fetch headers for spresdsheet api and the oauth setup so first time you run it google will ask for permissions. Specify return type as json as is trivial to parse it. – Zig Mandel Mar 12 '14 at 04:17
  • Thanks for your comments and suggestions. Good to know that Visualization API isn't an option. I hadn't considered the QUERY formula before because I'll be running the query a number of times with different values to generate for example, a report for each instructor. But maybe I could set the formula up in a worksheet and manipulate the parameters via script. The source data is always growing but the querying (mostly) is needed at set times (once or twice a quarter), so #1 is also worth a look. – Carrie Mar 12 '14 at 16:32
  • As for #3, I don't want the data to be public - is that required to Publish to the Web? I'll also want to switch to the new Sheets because of the amount of data we'll be accumulating, but haven't yet. I'll let you know what works for me or if I have further questions. Thank you! – Carrie Mar 12 '14 at 16:37
  • #3 doesnt need to make the spreadsheet public. Gas UrlFetch will take of the oauth. You cant yet use new sheets to make such query. – Zig Mandel Mar 15 '14 at 19:25
  • I have a page displaying a givz chart. Now I want to programmaticaly generate and save that same chart. How do I do that ? As a hack, I tried creating a function which queries the page, but I get "You should turn on Javascript support."... – Marc Perrin-Pelletier Nov 22 '17 at 15:05
  • I've made the code for #3 (my answer here), worked only with "everyone with a link can view" option. – Max Makhrov Aug 15 '18 at 13:53
  • For those discovering this thread and interested in querying data without sharing the source Google Sheet here is an example of using UrlFetch and oauth token mentioned by @ZigMandel https://gist.github.com/tanaikech/053d3ebbe76fa7c0b5e80ea9d6396011#sample-script – mhawksey May 18 '22 at 09:38
3

I've managed to use UrlFetchApp to get the data.

  • The file must be shared publicly ("everyone with a link can view" is enough)

Usage

function test_getSheetsQueryResult()
{
  var fileId = '1WO3PEycHGtfG-yd4V-B6EfKkVYMC73EqDBPqgAqcz3k';
  var sheetName = 'Data';
  var rangeA1 = 'A1:H11';
  var sqlText = "select A, C, D, F, 'google' where E > 0";

  var res = getSheetsQueryResult_(fileId, sheetName, rangeA1, sqlText);
  Logger.log(res);      

}

Code:

/*   
  Types:

    Get             Return
    number    =>    number
    string    =>    string
    date      =>    string
    datetime  =>    string
    boolean   =>    boolean

  Note: 

    The function returns strings for dates because of 2 resons:
      1. The string is automatically converted into a date when pasted into the sheet
      2. There are multiple issues with dates (like different time zones) that could modify returned values
*/
function getSheetsQueryResult_(fileId, sheetName, rangeA1, sqlText)
{

  var file = SpreadsheetApp.openById(fileId);
  var sheetId = file.getSheetByName(sheetName).getSheetId();

  var request = 'https://docs.google.com/spreadsheets/d/' + fileId + '/gviz/tq?gid=' + sheetId + '&range=' + rangeA1 + '&tq=' + encodeURIComponent(sqlText);
  var result = UrlFetchApp.fetch(request).getContentText();     
  // get json object
  var from = result.indexOf("{");
  var to   = result.lastIndexOf("}")+1;  
  var jsonText = result.slice(from, to);  
  var parsedText = JSON.parse(jsonText);      

  // get types
  var types = [];
  var addType_ = function(col) { types.push(col.type); }
  var cols = parsedText.table.cols;
  cols.forEach(addType_);    

  // loop rows
  var rows = parsedText.table.rows;  
  var result = [];  
  var rowQuery = [];
  var eltQuery = {};
  var row = [];
  var nRows = rows[0].c.length;
  var type = '';
  for (var i = 0, l = rows.length; i < l; i++)
  {
    rowQuery = rows[i].c;
    row = [];
    // loop values   
    for (var k = 0; k < nRows; k++)
    {
      eltQuery = rowQuery[k];
      type = types[k];
      if (type === 'number') { row.push(parseInt(eltQuery.v)); }
      if (type === 'boolean' || type === 'string') { row.push(eltQuery.v); }
      else { row.push(eltQuery.f); }      
    }    
    result.push(row);
  }

  return result;

}
Max Makhrov
  • 17,309
  • 5
  • 55
  • 81