الجداول المحورية

يوضّح هذا الدليل كيفية استخدام Google Sheets API ولماذا لإنشاء جداول محورية في جداول البيانات.

ما هو الجدول المحوري؟

توفّر الجداول المحورية طريقة لتلخيص البيانات في جدول البيانات، حيث يتم تلقائيًا تجميع البيانات أو فرزها أو حسابها أو إيجاد متوسطها، مع عرض النتائج الملخّصة في جدول جديد. يعمل الجدول المحوري كنوع من طلب البحث مقابل مجموعة بيانات مصدر. تكون بيانات المصدر هذه موجودة في مكان آخر في جدول البيانات، ويعرض الجدول المحوري طريقة عرض معالَجة للبيانات.

على سبيل المثال، لنفترض مجموعة بيانات المبيعات التالية:

A ب C D ج ح G
1 فئة العنصر رقم الطراز التكلفة الكمية المنطقة مندوب مبيعات تاريخ الشحن
2 العجلة W-24 $20.50 4 الغرب Beth ‎2016/3/1
3 باب D-01X $15.00 2 الجنوب Amir ‎2016/3/15
4 المحرّك ENG-0134 $100.00 1 الشمال Carmen ‎2016/3/20
5 إطار FR-0B1 $34.00 8 الشرق Hannah ‎2016/3/12
6 اللوحة P-034 ‫6.00 دولار أمريكي 4 الشمال Devyn ‎2016/4/2
7 اللوحة P-052 $11.50 7 الشرق إريك ‎2016/5/16
8 العجلة W-24 $20.50 11 الجنوب Sheldon ‎2016/4/30
9 المحرّك ENG-0161 $330.00 2 الشمال Jessie ‎2016/7/2
10 باب D-01Y $29.00 6 الغرب Armando ‎2016/3/13
11 إطار FR-0B1 $34.00 9 الجنوب Yuliana ‎2016/2/27
12 اللوحة P-102 $3,00 15 الغرب Carmen ‎2016/4/18
13 اللوحة P-105 $8.25 13 الغرب Jessie ‎2016/6/20
14 المحرّك ENG-0211 $283.00 1 الشمال Amir ‎2016/6/21
15 باب D-01X $15.00 2 الغرب Armando ‎2016/7/3
16 إطار FR-0B1 $34.00 6 الجنوب Carmen ‎2016/7/15
17 العجلة W-25 $20.00 8 الجنوب Hannah ‎2016/5/2
18 العجلة W-11 $29.00 13 الشرق إريك ‎2016/5/19
19 باب D-05 $17.70 7 الغرب Beth ‎2016/6/28
20 إطار FR-0B1 $34.00 8 الشمال Sheldon ‎2016/3/30

يمكنك استخدام جدول محوري لإنشاء تقرير يعرض عدد كل رقم طراز تم بيعه في كل منطقة:

لقطة شاشة لجدول محوري يعرض عدد أرقام الطرازات حسب المنطقة

للاطّلاع على رمز المصدر المستخدَم لإنشاء هذا الجدول المحوري، يُرجى الانتقال إلى قسم مثال أدناه.

بعد وضع جدول محوري في جدول بيانات، يمكن للمستخدمين تغيير بنية الملخّص وتفاصيله بشكل تفاعلي باستخدام واجهة مستخدم "جداول بيانات Google".

العمل باستخدام الجداول المحورية

يرتبط تعريف الجدول المحوري بخلية واحدة في ورقة بيانات. على الرغم من أنّ مظهره المعروض يتألف من خلايا متعددة من حيث الارتفاع والعرض، فإنّه من الناحية البرمجية يقع في إحداثيات خلية واحدة. تصبح هذه الخلية الزاوية العليا اليسرى من الجدول المحوري المعروض، ويتم تحديد نطاقه الأفقي والعمودي من خلال تعريفه.

إضافة جدول محوري

لإضافة جدول محوري، استخدِم طريقة batchUpdate ، مع تقديم طلب updateCells. يمكنك استخدام هذا الطلب لتقديم تعريف PivotTable كمحتوى لخلية كما هو موضّح أدناه:

{
  "updateCells": {
    "rows": {
      "values": [
        {
          "pivotTable": "MyPivotTable"
        }
      ],
      "start": {
        "sheetId": "sheetId",
        "rowIndex": 0,
        "columnIndex": 0
      },
      "fields": "pivotTable"
    }
  }
}

يؤدي هذا إلى وضع الجدول المحوري الذي تصفه MyPivotTable في ورقة البيانات المحدّدة، مع وضع الزاوية العليا اليمنى في الخلية A1. (يكون ارتفاع الجدول المحوري وعرضه ديناميكيَين، ولا تحدّد سوى المصدر).

يتيح لك نوع PivotTable تحديد ما يلي:

  • نطاق بيانات المصدر
  • حقل واحد أو أكثر ستشكّل بياناته صفوف الجدول المحوري
  • حقل واحد أو أكثر ستشكّل بياناته أعمدة الجدول المحوري
  • معايير الفلترة والتجميع
  • تنسيق الجدول المحوري

تعديل الجداول المحورية وحذفها

لا تتوفّر طلبات صريحة لتعديل جدول محوري أو حذفه. بدلاً من ذلك، استخدِم طلب updateCells بمحتويات خلايا مختلفة:

  • لتعديل جدول محوري، أنشئ تعريف PivotTable معدَّلاً وعدِّل الخلية باستخدام هذا التعريف، على غرار إضافة جدول محوري جديد.
  • لحذف جدول محوري، عدِّل الخلية باستخدام قيم فارغة. للاطّلاع على مثال، يُرجى الانتقال إلى نموذج حذف جدول محوري.

حالات الاستخدام

تتوفّر العديد من الاستخدامات المختلفة للجداول المحورية، في مجموعة واسعة من المجالات، بما في ذلك التحليل الإحصائي وتطبيقات تخطيط موارد المؤسسة (ERP) والتقارير المالية وغيرها. تشمل حالات الاستخدام الكلاسيكية للجدول المحوري ما يلي:

  • إجمالي المبيعات حسب المنطقة والربع السنوي
  • متوسط الراتب حسب المسمى الوظيفي والموقع الجغرافي
  • عدد الحوادث حسب المنتج والوقت من اليوم

إنّ عدد التطبيقات المحتمَلة للجداول المحورية كبير، كما أنّ القدرة على إنشائها برمجيًا قوية. يمكنك إنشاء جداول محورية تتيح الاستكشاف التفاعلي ولكنها مصمّمة خصيصًا لظروف معيّنة، على سبيل المثال:

  • استكشاف بيانات الحوادث لآخر 24 ساعة
  • عرض البيانات المجمَّعة أو تحليلها المقابلة للحساب المحدّد
  • فحص بيانات المبيعات للمناطق التابعة للمستخدم الحالي

مثال

ينشئ هذا المثال جدولاً محوريًا من مجموعة بيانات لإنتاج تقرير "رقم الطراز حسب المنطقة" الموضّح في مقدّمة هذه الصفحة. للاطّلاع على أمثلة إضافية ، يُرجى الانتقال إلى صفحة نموذج الجدول المحوري.

برمجة التطبيقات

sheets/api/spreadsheet_snippets.gs
/**
 * Create pivot table
 * @param {string} spreadsheetId spreadsheet ID
 * @returns {*} pivot table's spreadsheet
 */
Snippets.prototype.pivotTable = (spreadsheetId) => {
  try {
    const spreadsheet = SpreadsheetApp.openById(spreadsheetId);

    // Create two sheets for our pivot table, assume we have one.
    const sheet = spreadsheet.getSheets()[0];
    sheet.copyTo(spreadsheet);

    const sourceSheetId = spreadsheet.getSheets()[0].getSheetId();
    const targetSheetId = spreadsheet.getSheets()[1].getSheetId();

    // Create pivot table
    const pivotTable = Sheets.newPivotTable();

    const gridRange = Sheets.newGridRange();
    gridRange.sheetId = sourceSheetId;
    gridRange.startRowIndex = 0;
    gridRange.startColumnIndex = 0;
    gridRange.endRowIndex = 20;
    gridRange.endColumnIndex = 7;
    pivotTable.source = gridRange;

    const pivotRows = Sheets.newPivotGroup();
    pivotRows.sourceColumnOffset = 1;
    pivotRows.showTotals = true;
    pivotRows.sortOrder = "ASCENDING";
    pivotTable.rows = pivotRows;

    const pivotColumns = Sheets.newPivotGroup();
    pivotColumns.sourceColumnOffset = 4;
    pivotColumns.sortOrder = "ASCENDING";
    pivotColumns.showTotals = true;
    pivotTable.columns = pivotColumns;

    const pivotValue = Sheets.newPivotValue();
    pivotValue.summarizeFunction = "COUNTA";
    pivotValue.sourceColumnOffset = 4;
    pivotTable.values = [pivotValue];

    // Create other metadata for the updateCellsRequest
    const cellData = Sheets.newCellData();
    cellData.pivotTable = pivotTable;

    const rows = Sheets.newRowData();
    rows.values = cellData;

    const start = Sheets.newGridCoordinate();
    start.sheetId = targetSheetId;
    start.rowIndex = 0;
    start.columnIndex = 0;

    const updateCellsRequest = Sheets.newUpdateCellsRequest();
    updateCellsRequest.rows = rows;
    updateCellsRequest.start = start;
    updateCellsRequest.fields = "pivotTable";

    // Batch update our spreadsheet
    const batchUpdate = Sheets.newBatchUpdateSpreadsheetRequest();
    const updateCellsRawRequest = Sheets.newRequest();
    updateCellsRawRequest.updateCells = updateCellsRequest;
    batchUpdate.requests = [updateCellsRawRequest];
    const response = Sheets.Spreadsheets.batchUpdate(
      batchUpdate,
      spreadsheetId,
    );

    return response;
  } catch (err) {
    // TODO (developer) - Handle exception
    console.log("Failed with error %s", err.message);
  }
};

جافا

sheets/snippets/src/main/java/PivotTables.java
import com.google.api.client.googleapis.json.GoogleJsonError;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.sheets.v4.Sheets;
import com.google.api.services.sheets.v4.SheetsScopes;
import com.google.api.services.sheets.v4.model.AddSheetRequest;
import com.google.api.services.sheets.v4.model.BatchUpdateSpreadsheetRequest;
import com.google.api.services.sheets.v4.model.BatchUpdateSpreadsheetResponse;
import com.google.api.services.sheets.v4.model.CellData;
import com.google.api.services.sheets.v4.model.GridCoordinate;
import com.google.api.services.sheets.v4.model.GridRange;
import com.google.api.services.sheets.v4.model.PivotGroup;
import com.google.api.services.sheets.v4.model.PivotTable;
import com.google.api.services.sheets.v4.model.PivotValue;
import com.google.api.services.sheets.v4.model.Request;
import com.google.api.services.sheets.v4.model.RowData;
import com.google.api.services.sheets.v4.model.UpdateCellsRequest;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/* Class to demonstrate the use of Spreadsheet Create Pivot Tables API */
public class PivotTables {
  /**
   * Create pivot table.
   *
   * @param spreadsheetId - Id of the spreadsheet.
   * @return pivot table's spreadsheet
   * @throws IOException - if credentials file not found.
   */
  public static BatchUpdateSpreadsheetResponse pivotTables(String spreadsheetId)
      throws IOException {
        /* Load pre-authorized user credentials from the environment.
           TODO(developer) - See https://developers.google.com/identity for
            guides on implementing OAuth2 for your application. */
    GoogleCredentials credentials = GoogleCredentials.getApplicationDefault()
        .createScoped(Collections.singleton(SheetsScopes.SPREADSHEETS));
    HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(
        credentials);

    // Create the sheets API client
    Sheets service = new Sheets.Builder(new NetHttpTransport(),
        GsonFactory.getDefaultInstance(),
        requestInitializer)
        .setApplicationName("Sheets samples")
        .build();

    // Create two sheets for our pivot table.
    List<Request> sheetsRequests = new ArrayList<>();
    BatchUpdateSpreadsheetResponse result = null;
    try {
      sheetsRequests.add(new Request().setAddSheet(new AddSheetRequest()));
      sheetsRequests.add(new Request().setAddSheet(new AddSheetRequest()));

      BatchUpdateSpreadsheetRequest createSheetsBody = new BatchUpdateSpreadsheetRequest()
          .setRequests(sheetsRequests);
      BatchUpdateSpreadsheetResponse createSheetsResponse = service.spreadsheets()
          .batchUpdate(spreadsheetId, createSheetsBody).execute();
      int sourceSheetId = createSheetsResponse.getReplies().get(0).getAddSheet().getProperties()
          .getSheetId();
      int targetSheetId = createSheetsResponse.getReplies().get(1).getAddSheet().getProperties()
          .getSheetId();

      PivotTable pivotTable = new PivotTable()
          .setSource(
              new GridRange()
                  .setSheetId(sourceSheetId)
                  .setStartRowIndex(0)
                  .setStartColumnIndex(0)
                  .setEndRowIndex(20)
                  .setEndColumnIndex(7)
          )
          .setRows(Collections.singletonList(
              new PivotGroup()
                  .setSourceColumnOffset(1)
                  .setShowTotals(true)
                  .setSortOrder("ASCENDING")
          ))
          .setColumns(Collections.singletonList(
              new PivotGroup()
                  .setSourceColumnOffset(4)
                  .setShowTotals(true)
                  .setSortOrder("ASCENDING")
          ))
          .setValues(Collections.singletonList(
              new PivotValue()
                  .setSummarizeFunction("COUNTA")
                  .setSourceColumnOffset(4)
          ));
      List<Request> requests = Lists.newArrayList();
      Request updateCellsRequest = new Request().setUpdateCells(new UpdateCellsRequest()
          .setFields("*")
          .setRows(Collections.singletonList(
              new RowData().setValues(
                  Collections.singletonList(
                      new CellData().setPivotTable(pivotTable))
              )
          ))
          .setStart(new GridCoordinate()
              .setSheetId(targetSheetId)
              .setRowIndex(0)
              .setColumnIndex(0)

          ));

      requests.add(updateCellsRequest);
      BatchUpdateSpreadsheetRequest updateCellsBody = new BatchUpdateSpreadsheetRequest()
          .setRequests(requests);
      result = service.spreadsheets().batchUpdate(spreadsheetId, updateCellsBody).execute();
    } catch (GoogleJsonResponseException e) {
      // TODO(developer) - handle error appropriately
      GoogleJsonError error = e.getDetails();
      if (error.getCode() == 404) {
        System.out.printf("Spreadsheet not found with id '%s'.\n", spreadsheetId);
      } else {
        throw e;
      }
    }
    return result;
  }
}

JavaScript

sheets/snippets/sheets_pivot_tables.js
function pivotTable(spreadsheetId, callback) {
  // Create two sheets for our pivot table
  const requests = [{
    addSheet: {},
  }, {
    addSheet: {},
  }];
  const batchUpdateRequest = {requests: requests};
  try {
    gapi.client.sheets.spreadsheets.batchUpdate({
      spreadsheetId: spreadsheetId,
      resource: batchUpdateRequest,
    }).then((response) => {
      const sourceSheetId = response.result.replies[0].addSheet.properties.sheetId;
      const targetSheetId = response.result.replies[1].addSheet.properties.sheetId;

      const requests = [{
        updateCells: {
          rows: {
            values: [{
              pivotTable: {
                source: {
                  sheetId: sourceSheetId,
                  startRowIndex: 0,
                  startColumnIndex: 0,
                  endRowIndex: 20,
                  endColumnIndex: 7,
                },
                rows: [{
                  sourceColumnOffset: 1,
                  showTotals: true,
                  sortOrder: 'ASCENDING',
                }],
                columns: [{
                  sourceColumnOffset: 4,
                  sortOrder: 'ASCENDING',
                  showTotals: true,
                }],
                values: [{
                  summarizeFunction: 'COUNTA',
                  sourceColumnOffset: 4,
                }],
                valueLayout: 'HORIZONTAL',
              },
            },
            ],
          },
          start: {
            sheetId: targetSheetId,
            rowIndex: 0,
            columnIndex: 0,
          },
          fields: 'pivotTable',
        },
      }];

      const body = {
        requests,
      };
      gapi.client.sheets.spreadsheets.batchUpdate({
        spreadsheetId: spreadsheetId,
        resource: body,
      }).then((response) => {
        if (callback) callback(response);
      });
    });
  } catch (err) {
    document.getElementById('content').innerText = err.message;
    return;
  }
}

Node.js

sheets/snippets/sheets_pivot_table.js
import {GoogleAuth} from 'google-auth-library';
import {google} from 'googleapis';

/**
 * Creates a pivot table in a spreadsheet.
 * @param {string} spreadsheetId The ID of the spreadsheet.
 * @return {Promise<object>} The response from the batch update.
 */
async function pivotTable(spreadsheetId) {
  // Authenticate with Google and get an authorized client.
  const auth = new GoogleAuth({
    scopes: 'https://www.googleapis.com/auth/spreadsheets',
  });

  const service = google.sheets({version: 'v4', auth});

  // Create two new sheets for the pivot table.
  // One for the source data and one for the pivot table itself.
  let requests = [
    {
      addSheet: {},
    },
    {
      addSheet: {},
    },
  ];
  let resource = {requests};
  let response = await service.spreadsheets.batchUpdate({
    spreadsheetId,
    resource,
  });

  // Get the IDs of the newly created sheets.
  const sourceSheetId = response.data.replies[0].addSheet.properties.sheetId;
  const targetSheetId = response.data.replies[1].addSheet.properties.sheetId;

  // Add a pivot table to the new sheet.
  requests = [
    {
      updateCells: {
        rows: {
          values: [
            {
              pivotTable: {
                // The source data for the pivot table.
                source: {
                  sheetId: sourceSheetId,
                  startRowIndex: 0,
                  startColumnIndex: 0,
                  endRowIndex: 20,
                  endColumnIndex: 7,
                },
                // The rows of the pivot table.
                rows: [
                  {
                    sourceColumnOffset: 1,
                    showTotals: true,
                    sortOrder: 'ASCENDING',
                  },
                ],
                // The columns of the pivot table.
                columns: [
                  {
                    sourceColumnOffset: 4,
                    sortOrder: 'ASCENDING',
                    showTotals: true,
                  },
                ],
                // The values to display in the pivot table.
                values: [
                  {
                    summarizeFunction: 'COUNTA',
                    sourceColumnOffset: 4,
                  },
                ],
                valueLayout: 'HORIZONTAL',
              },
            },
          ],
        },
        // The location to place the pivot table.
        start: {
          sheetId: targetSheetId,
          rowIndex: 0,
          columnIndex: 0,
        },
        fields: 'pivotTable',
      },
    },
  ];
  resource = {
    requests,
  };

  // Send the batch update request to create the pivot table.
  response = service.spreadsheets.batchUpdate({
    spreadsheetId,
    resource,
  });
  return response;
}

PHP

sheets/snippets/src/SpreadsheetPivotTables.php
<?php
use Google\Client;
use Google\Service\Drive;
use Google\Service\Sheets\BatchUpdateSpreadsheetRequest;


function pivotTables($spreadsheetId)
    {
        /* Load pre-authorized user credentials from the environment.
           TODO(developer) - See https://developers.google.com/identity for
            guides on implementing OAuth2 for your application. */
        $client = new Google\Client();
        $client->useApplicationDefaultCredentials();
        $client->addScope(Google\Service\Drive::DRIVE);
        $service = new Google_Service_Sheets($client);
        try{
            $requests = [
                new Google_Service_Sheets_Request([
                    'addSheet' => [
                        'properties' => [
                            'title' => 'Sheet 1'
                            ]
                ]
            ]),
            new Google_Service_Sheets_Request([
                'addSheet' => [
                    'properties' => [
                        'title' => 'Sheet 2'
                        ]
                        ]
                        ])
                    ];
                    // Create two sheets for our pivot table
                    $batchUpdateRequest = new Google_Service_Sheets_BatchUpdateSpreadsheetRequest([
                        'requests' => $requests
                    ]);
        $batchUpdateResponse = $service->spreadsheets->batchUpdate($spreadsheetId, $batchUpdateRequest);
        $sourceSheetId = $batchUpdateResponse->replies[0]->addSheet->properties->sheetId;
        $targetSheetId = $batchUpdateResponse->replies[1]->addSheet->properties->sheetId;
        $requests = [
            'updateCells' => [
                'rows' => [
                    'values' => [
                        [
                            'pivotTable' => [
                                'source' => [
                                    'sheetId' => $sourceSheetId,
                                    'startRowIndex' => 0,
                                    'startColumnIndex' => 0,
                                    'endRowIndex' => 20,
                                    'endColumnIndex' => 7
                                ],
                                'rows' => [
                                    [
                                        'sourceColumnOffset' => 1,
                                        'showTotals' => true,
                                        'sortOrder' => 'ASCENDING',
                                    ],
                                ],
                                'columns' => [
                                    [
                                        'sourceColumnOffset' => 4,
                                        'sortOrder' => 'ASCENDING',
                                        'showTotals' => true,
                                    ]
                                ],
                                'values' => [
                                    [
                                        'summarizeFunction' => 'COUNTA',
                                        'sourceColumnOffset' => 4
                                        ]
                                    ],
                                'valueLayout' => 'HORIZONTAL'
                            ]
                        ]
                        ]
                ],
                'start' => [
                    'sheetId' => $targetSheetId,
                    'rowIndex' => 0,
                    'columnIndex' => 0
                ],
                'fields' => 'pivotTable'
            ]
        ];
        return $batchUpdateResponse;
    }
        catch(Exception $e) {
            // TODO(developer) - handle error appropriately
            echo 'Message: ' .$e->getMessage();
        }
    }

Python

sheets/snippets/sheets_pivot_tables.py
import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError


def pivot_tables(spreadsheet_id):
  """
  Creates the batch_update the user has access to.
  Load pre-authorized user credentials from the environment.
  TODO(developer) - See https://developers.google.com/identity
  for guides on implementing OAuth2 for the application.
  """
  creds, _ = google.auth.default()
  # pylint: disable=maybe-no-member
  try:
    service = build("sheets", "v4", credentials=creds)
    # Create two sheets for our pivot table.
    body = {"requests": [{"addSheet": {}}, {"addSheet": {}}]}
    batch_update_response = (
        service.spreadsheets()
        .batchUpdate(spreadsheetId=spreadsheet_id, body=body)
        .execute()
    )
    source_sheet_id = (
        batch_update_response.get("replies")[0]
        .get("addSheet")
        .get("properties")
        .get("sheetId")
    )
    target_sheet_id = (
        batch_update_response.get("replies")[1]
        .get("addSheet")
        .get("properties")
        .get("sheetId")
    )
    requests = []
    requests.append(
        {
            "updateCells": {
                "rows": {
                    "values": [
                        {
                            "pivotTable": {
                                "source": {
                                    "sheetId": source_sheet_id,
                                    "startRowIndex": 0,
                                    "startColumnIndex": 0,
                                    "endRowIndex": 20,
                                    "endColumnIndex": 7,
                                },
                                "rows": [
                                    {
                                        "sourceColumnOffset": 1,
                                        "showTotals": True,
                                        "sortOrder": "ASCENDING",
                                    },
                                ],
                                "columns": [{
                                    "sourceColumnOffset": 4,
                                    "sortOrder": "ASCENDING",
                                    "showTotals": True,
                                }],
                                "values": [{
                                    "summarizeFunction": "COUNTA",
                                    "sourceColumnOffset": 4,
                                }],
                                "valueLayout": "HORIZONTAL",
                            }
                        }
                    ]
                },
                "start": {
                    "sheetId": target_sheet_id,
                    "rowIndex": 0,
                    "columnIndex": 0,
                },
                "fields": "pivotTable",
            }
        }
    )
    body = {"requests": requests}
    response = (
        service.spreadsheets()
        .batchUpdate(spreadsheetId=spreadsheet_id, body=body)
        .execute()
    )
    return response

  except HttpError as error:
    print(f"An error occurred: {error}")
    return error


if __name__ == "__main__":
  # Pass: spreadsheet_id
  pivot_tables("1CM29gwKIzeXsAppeNwrc8lbYaVMmUclprLuLYuHog4k")

Ruby

sheets/snippets/lib/spreadsheet_snippets.rb
requests = [{
  update_cells: {
    rows:   {
      values: [
        {
          pivot_table: {
            source:       {
              sheet_id:           source_sheet_id,
              start_row_index:    0,
              start_column_index: 0,
              end_row_index:      20,
              end_column_index:   7
            },
            rows:         [
              {
                source_column_offset: 1,
                show_totals:          true,
                sort_order:           'ASCENDING',
              },
            ],
            columns:      [
              {
                source_column_offset: 4,
                sort_order:           'ASCENDING',
                show_totals:          true,
              }
            ],
            values:       [
              {
                summarize_function:   'COUNTA',
                source_column_offset: 4
              }
            ],
            value_layout: 'HORIZONTAL'
          }
        }
      ]
    },
    start:  {
      sheet_id:     target_sheet_id,
      row_index:    0,
      column_index: 0
    },
    fields: 'pivotTable'
  }
}]
result = service.batch_update_spreadsheet(spreadsheet_id, body, {})