将 Bigquery 结果批量更新为 google 表(大约 50k 个结果)

Batch Update Bigquery results into google sheets(about 50k results)

我正在尝试使用脚本编辑器(Apps 脚本)将 BigQuery 结果流式传输到 google 工作表中。我正在关注这些 [文档][1] .

我遇到的问题是,数据未完全加载,挂起。我有很多行(超过 12 行)。我想我需要通过某种批量更新来优化“附加结果”部分。现在这是一个循环,我猜它不是很有效。 我想不明白。我尝试使用“.next()”但出现错误,函数不存在。我使用这些 [document][2].

如何优化附加结果部分? 这是整个代码(稍后我只包含了我要修改的部分):

  
  var ui = SpreadsheetApp.getUi();
  ui.createMenu("Update")
      .addItem('Update','update')
      .addToUi();
}


function update() {
  
  run1("\"Filter1\"","\"FilterA\"","Sheet1);
  run1("\"Filter2\"","\"FilterB\"","Sheet2");

  
};


function run1(filter1,filter2,output) {
  
  var projectId = 'xxx';
  var request = {
    useLegacySql: false,
    useQueryCache: false,
    query: 'select * from table ' +
           'where a1.col1 = ' + filter1 + ' and a1.col2  in ( ' + filter2 + ' ); ' 
     
  };
  
  var queryResults = BigQuery.Jobs.query(request, projectId);
  var jobId = queryResults.jobReference.jobId;
  


  // Check on status of the Query Job.
  var sleepTimeMs = 500;
  while (!queryResults.jobComplete) {
    Utilities.sleep(sleepTimeMs);
    sleepTimeMs *= 2;
    queryResults = BigQuery.Jobs.getQueryResults(projectId,jobId);
  }

  // Get all the rows of results.
  var rows = queryResults.rows;
  while (queryResults.pageToken) {
    queryResults = BigQuery.Jobs.getQueryResults(projectId,jobId, {
      pageToken: queryResults.pageToken
    });
    rows = rows.concat(queryResults.rows);
  }

  if (rows) {
    var spreadsheet = SpreadsheetApp.getActive();
    var sheet = spreadsheet.getSheetByName(output);
    sheet.clearContents();
    
    // Append the headers.
    var headers = queryResults.schema.fields.map(function(field) {
      return field.name;
    });
    sheet.appendRow(headers);

    spreadsheet.getSheetByName(output).getRange("C1").setValue("Modified_col_name");

    // Append the results.
    var data = new Array(rows.length);
    for (var i = 0; i < rows.length; i++) {
      var cols = rows[i].f;
      data[i] = new Array(cols.length);
      for (var j = 0; j < cols.length; j++) {
        data[i][j] = cols[j].v;
      }
    }

   


    sheet.getRange(2, 1, rows.length, headers.length).setValues(data);

    Logger.log("Results spreadsheet created: %s",
        spreadsheet.getUrl());
  } else {
    Logger.log("No rows returned.");
  }
};

具体这部分代码:

for (var i = 0; i < rows.length; i++) {
      var cols = rows[i].f;
      data[i] = new Array(cols.length);
      for (var j = 0; j < cols.length; j++) {
        data[i][j] = cols[j].v;
      }
    }

您需要在查询中使用更多过滤器或指定更少的列数。因为你可能犯的错误之一是 文件大小超过 10MB。因为在这种情况下行的限制是 50,000 行,所以在 12,000 或 15,000 行之间会出现错误。您可以将数据拆分为多个 google 工作表。

在这里您可以看到一些解决方案,您还可以在 this link 中看到更多文档。

您的查询结果可能太大。如果出现以下情况,您的查询将失败:

数据透视表有超过 50K 个结果。为了减少查询结果,您 可以:

  • 使用过滤器限制结果
  • 限制每个突破的行数
  • 添加行、列、值和过滤器时关闭“显示总计”
  • 结果大小超过 10MB。要减小大小,return 行或 列。

我相信你的目标如下。

  • 您想减少脚本的处理成本。

这样的话,下面的修改怎么样?

修改后的脚本:

在您使用此脚本之前,please enable Sheets API at Advanced Google services

发件人:

if (rows) {
  var spreadsheet = SpreadsheetApp.getActive();
  var sheet = spreadsheet.getSheetByName(output);
  sheet.clearContents();
  
  // Append the headers.
  var headers = queryResults.schema.fields.map(function(field) {
    return field.name;
  });
  sheet.appendRow(headers);

  spreadsheet.getSheetByName(output).getRange("C1").setValue("Modified_col_name");

  // Append the results.
  var data = new Array(rows.length);
  for (var i = 0; i < rows.length; i++) {
    var cols = rows[i].f;
    data[i] = new Array(cols.length);
    for (var j = 0; j < cols.length; j++) {
      data[i][j] = cols[j].v;
    }
  }

 


  sheet.getRange(2, 1, rows.length, headers.length).setValues(data);

  Logger.log("Results spreadsheet created: %s",
      spreadsheet.getUrl());
} else {
  Logger.log("No rows returned.");
}

收件人:

if (rows) {
  var headers = queryResults.schema.fields.map(function (field) {
    return field.name;
  });
  var data = [headers, ...rows.map(({ f }) => f.map(({ v }) => v || ""))];
  var spreadsheet = SpreadsheetApp.getActive();
  var sheet = spreadsheet.getSheetByName(output);
  sheet.clearContents();
  SpreadsheetApp.flush();
  Sheets.Spreadsheets.Values.update({ values: data }, spreadsheet.getId(), output, { valueInputOption: "USER_ENTERED" });
  // spreadsheet.getSheetByName(output).getRange("C1").setValue("Modified_col_name"); // I'm not sure about this line.
  Logger.log("Results spreadsheet created: %s", spreadsheet.getUrl());
} else {
  Logger.log("No rows returned.");
}

参考: