【问题标题】:How to build a custom report from Google Sheets如何从 Google 表格构建自定义报告
【发布时间】:2020-06-22 19:01:33
【问题描述】:

我在谷歌上搜索了一种从数据电子表格构建报告的方法,似乎 google data studiogoogle sheet 是实现这一目标的一种选择。 p>

尽管有一些使用 LibreOffice Calc 的经验,但我还是 Google Sheets 和 DataStudio 的新手。

我在 Google 表格中的数据是:

我想建立的报告,当新数据到达谷歌表时必须更新(比如说,每天左右)。

我只是为字段名称(objId;objDesc;objMore;objProgress;taskId;taskDesc;taskMore;event)着色,并将数据分类到电子表格中,以便于理解我想要实现的目标。 p>

感谢您的帮助。

【问题讨论】:

  • 如果您将其视为关系表,您会发现有三个表,它们的字段:Object objId;对象描述;对象更多;对象进度。任务taskId;任务描述;任务更多。事件对象标识;任务标识;事件。
  • 嗨!您只想使用 Data Studio 还是只想使用 Data Studio 来创建报告?因为您可以在不需要 Data Studio 的情况下仅使用电子表格和应用程序脚本来创建报告。您愿意接受使用其中任何一种的解决方案吗?另外,您想在每次有新数据进入时创建报告,对吗?您希望这些报告以 PDF 格式下载还是通过 Gmail 发送?
  • 嗨 Mateo,是的,我愿意接受使用 google 电子表格和应用脚本的解决方案。是的,每次电子表格中包含新行时,报告都会更新,或者我单击一个按钮来更新报告。我期待你的指示。感谢您的回复。

标签: google-sheets google-data-studio


【解决方案1】:

解决方案

因此,基本上,您希望在单击按钮时按所述顺序生成对象、任务和事件的层次结构报告。

在此解决方案中,我提供了最复杂部分所需的代码,然后提供了其余步骤的指导。

  1. Insert->Drawing中的数据向您的工作表添加一个按钮,然后绘制您的按钮。
  2. 创建一个新工作表并插入以下公式,如图所示:
=iferror(ArrayFormula(lookup(unique(Sheet1!A1:A),Sheet1!A1:A,row(Sheet1!A1:A)+1)))

=iferror(ArrayFormula(lookup(unique(Sheet1!E2:E),Sheet1!E2:E,row(Sheet1!E2:E)+1)))

这些论坛基本上会检测指定列(在我们的例子中是对象 ID 和任务 ID 的列)中值的任何变化,这将有助于生成报告。

  1. 在此之后,通过脚本编辑器并使用以下函数生成对象数组,其中包含按层次排序的正确数据。以下代码包含自我解释的 cmets。这是最棘手的部分,它利用之前创建的工作表来了解我们的对象和任务 ID 在哪里发生变化,并将正确的信息存储在正确的位置。

对于这个数据:

这将是运行函数后生成的对象:

 [{ObjectId=1.0, 1={TaskId=S02, Events=[[3242.0]], TaskMore=ppp, Description=ppp}, 0={TaskId=S01, Description=qqq, Events=[[1.0], [23.0], [324.0]], TaskMore=qqq}, ObjectMore=aaaa, ObjectDesc=aaaa, 2={TaskMore=lll, Events=[[3.0]], TaskId=S03, Description=lll}, ObjectProgress=0.7}, {3={Description=www, Events=[[43.0]], TaskMore=www, TaskId=T01}, 5={TaskId=T03, Events=[[5.0]], TaskMore=ttt, Description=ttt}, ObjectMore=bbbb, 4={Description=eee, TaskId=T02, TaskMore=eee, Events=[[54.0], [4.0]]}, ObjectDesc=bbbb, 6={Description=yyy, Events=[[345.0], [343.0]], TaskId=T04, TaskMore=yyy}, ObjectProgress=0.33, ObjectId=2.0}]

function myFunction() {
  // Get sheets
  var sheetData = SpreadsheetApp.getActive().getSheetByName('Sheet1');
  var sheetHelp = SpreadsheetApp.getActive().getSheetByName('Sheet2');
  
  // This is the array where we will be storing our info
  var Objects = []
  // Get the ranges of values from our helper sheet that detect changes in that column
  var ObjectIds = sheetHelp.getRange(2, 1,sheetHelp.getLastRow(),1).getValues().flat();
  var TaskIds = sheetHelp.getRange(2, 2,sheetHelp.getLastRow(),2).getValues().flat();
  
  // Delete all the blank elements in the flaten array of values
  ObjectIds = ObjectIds.filter(item => item);
  TaskIds = TaskIds.filter(item => item);
  
  // Delete the last item as this would just be the change between a value and a blank cell
  ObjectIds.pop();
  TaskIds.pop();

  // Lets iterate through all our main objects detected
  for(i=0;i<ObjectIds.length;i++){
    // for each object insert its details and information
    Objects.push({
      ObjectId: sheetData.getRange(parseInt(ObjectIds[i]), 1).getValue(),
      ObjectDesc : sheetData.getRange(parseInt(ObjectIds[i]), 2).getValue(),
      ObjectMore : sheetData.getRange(parseInt(ObjectIds[i]), 3).getValue(),
      ObjectProgress : sheetData.getRange(parseInt(ObjectIds[i]), 4).getValue()   
    });
    // for each object iterate through all its possible tasks
    for(j=0;j<TaskIds.length;j++){
      // get the last row value as for the last element of the tasks if we do not have anything it will 
      // have issues in the following if condition if this is null
      var lastRow = sheetHelp.getLastRow();
      ObjectIds.push(lastRow);
      
      // If the task is within the object index range (i.e for an object between indices 8 and 12
      // his tasks are those between these indices as well
      if(TaskIds[j]<ObjectIds[i+1] && TaskIds[j]>=ObjectIds[i]){
        TaskIds.push(lastRow);
        
        // get all the events for this specific task checking that they are within the indices
        // of the task itself (only events that are within the index boundaries of the task
        var events = sheetData.getRange(TaskIds[j], 8,TaskIds[j+1]-TaskIds[j],1).getValues();
        
        // add the new task object
        Objects[i][j] = {
          TaskId : sheetData.getRange(parseInt(TaskIds[j]),5).getValue(),
          Description : sheetData.getRange(parseInt(TaskIds[j]),6).getValue(),
          TaskMore : sheetData.getRange(parseInt(TaskIds[j]),7).getValue(),
          Events : events
        };
        TaskIds.pop();
      }
      ObjectIds.pop();
    }
  }  
  downloadReport(Objects);
}
  1. 返回到您创建的按钮并在其分配脚本下的选项中选择我们的函数myFunction
  2. 一旦您拥有了包含正确分层信息的对象数组,您就可以自行决定使用它来生成报告的方式。您可以:
  • 使用 JSON 对象数组生成 HTML 电子邮件,以便在您单击工作表按钮时通过 Gmail 发送报告。
  • 生成一个新工作表并使用您在图片中显示的结构粘贴此数据(由于您已对数据进行了排序,因此更容易自动化),导出为 PDF 并删除此工作表,因为其目的只是生成此 PDF 报告.
  • 将其作为 JSON 数组发送给其他服务,以便他们轻松使用。

对于第五步的第二个场景,我在这里提供一些指导,作为如何实施的示例(一个最小的示例)。如果您需要进一步的指导,请告诉我。

基本上,您可以在电子表格中创建这个新工作表,然后遍历我们的对象数组和 json 对象,以将新工作表的单元格值设置在适当的位置。 请注意,我还编辑了之前的代码,我必须从 myFunction() 调用这个新函数

以下代码具有自我解释的 cmets,它基本上会打印工作表中存在的对象 ID:

function downloadReport(object){
  // Check if this sheet already exists from generating previous reports
  // and if so delete it to create a new report
  if(SpreadsheetApp.getActive().getSheetByName('Download')){SpreadsheetApp.getActive().deleteSheet(SpreadsheetApp.getActive().getSheetByName('Download'))}
  
  // Create your new sheet
  var sheet = SpreadsheetApp.getActive().insertSheet().setName('Download');
  
  // Iterate over each object in your array of objects
  for(i=0;i<object.length;i++){
  
  // print each object id of your series of objects. For doing so first access the array
  // element and then in that object access the key of the json object. Do the same for the 
  // rest of the fields you are interested to print in your report. 
    sheet.getRange(i+1, 1).setValue(object[i]['ObjectId']);
  } 
}

我希望这对您有所帮助。让我知道您是否需要其他任何内容,或者您​​是否不理解某些内容。 :)

【讨论】:

  • 嗨 Mateo,非常有趣的解决方案。我会尽快阅读、运行和反馈。感谢您的帮助。
  • 嗨 Mateo,我在您解释的第 5 步卡住了。我想知道您在第 5 步中的第二个选项,我的意思是:“生成一个新工作表并使用您在图片中显示的结构粘贴此数据......”我尝试过 (var sheetReport = SpreadsheetApp.getActive().getSheetByName(' my_new_sheet_name');) 在 App Script 中,但是我迷路了...
  • 嗨,我已经相应地编辑了我的答案,以指导您如何使用这些数据以正确的顺序将其打印在新的工作表中。希望对您有所帮助:D
  • 嗨 Mateo,它确实有很大帮助。谢谢。
猜你喜欢
  • 1970-01-01
  • 2010-10-08
  • 1970-01-01
  • 2017-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多