Google Apps Script Transpose & Cartesian Product - google-apps-script

I have been building a solution for project resource management in Google Sheets.
The idea is that the team manager would input the resource demand per project on a weekly level on a single row. This is a very user friendly and easy solution for the end user. See image below for a description of what the input sheet looks like.
Input_Sheet
Since my organization has multiple teams, we want to have a separate sheet for each team. In order to still keep the reporting centralized, I have connected each sheet into BigQuery where I am combining the data from different sheets and finally creating reports in Power BI.
Currently, I am using a mix of google functions such as QUERY, ARRAYFORMULA, SPLIT, FLATTEN to transpose the data into a database suitable format, which is presented in the image below. In order to have the data in a database, I need to transpose the data from a horizontal format into a vertical format.
Result_Sheet
My current issue is that there can be around 300 rows and 100 columns and at this point a simple google function is getting too heavy to run. I am now looking for a solution to do the processing using apps script, if that would prove to be a more efficient solution and would allow me to add some logic for how often the script is run.
Dear Experts, do you see that something like this would be possible to do in apps script and how should one do this? I have some coding experience, but I'm new to apps script. I am struggling especially with producing the Cartesian Product, which would allow me to link date with the demand.
I have added a link to my example sheet below.
Link to sheet: https://docs.google.com/spreadsheets/d/1XKyt3BAo5L2RsK2vYpqrlBuEZoehIztGJ_Nl2DN-h-8/edit?usp=sharing

Use an { array expression }, like this:
=arrayformula( query(
{
Input_Sheet!B2:D2 \ "Date" \ "Demand";
flatten( iferror(Input_Sheet!E3:H / 0; Input_Sheet!B3:B) ) \
flatten( iferror(Input_Sheet!E3:H / 0; Input_Sheet!C3:C) ) \
flatten( iferror(Input_Sheet!E3:H / 0; Input_Sheet!D3:D) ) \
flatten( to_date( iferror(Input_Sheet!E3:H / 0; Input_Sheet!E2:H2) ) ) \
flatten(Input_Sheet!E3:H)
};
"where Col5 is not null
order by Col1";
1
) )
This is not a Cartesian product. It is more like unpivot.
See the new Solution sheet in your sample spreadsheet.

Related

Find cell address of each matching value in range - Google Apps Script

I have a range that assigns shifts to a set of employees, in which the row labels are dates (ie, the Y axis is a chronological set of dates), and the column headers are locations (Building1, Building2, etc). Each row, then, contains employees assigned to each location for that day. Or, alternatively, each column will contain a chrono list of who will be assigned to the location specified in that column's header.
I am attempting to match a name, say "John Doe" for each instance he appears throughout the range, and return a 2 column list of dates and locations for which he is assigned. John Doe will be listed many times over the dates in question and various locations (in multiple columns).
I've reached the limit of my expertise both with AppsScript and Filter functions and greatly appreciate any help. I believe a loop is necessary, but perhaps there is a better way. For what its worth, my goal is to take this list and put every assignment on the user's calendar (I've solved for this already). TIA everyone!
Sample input and output situation
From your provided Spreadsheet, I believe your goal is as follows.
You want to achieve the following situation using Google Apps Script.
In this case, how about the following sample script?
Sample script:
Please copy and paste the following script to the script editor of Spreadsheet and save the script. When you use this script, please put a custom function of =SAMPLE(Data!A3:F20,"John Doe") to a cell. By this, the result values are returned.
const SAMPLE = ([h, ...v], searchName) =>
[["Data", "Location"], ...v.flatMap(([hh, ...vv]) => {
const i = vv.indexOf(searchName);
return i != -1 ? [[hh, h[i + 1]]] : [];
})];
If you don't want to include the header row, you can also use the following script.
const SAMPLE = ([h, ...v], searchName) =>
v.flatMap(([hh, ...vv]) => {
const i = vv.indexOf(searchName);
return i != -1 ? [[hh, h[i + 1]]] : [];
});
Testing:
When this sample script is used for your sample input values, the following situation is obtained.
In the case of "John Doe", from your expected output, "Building4" of "8/8/2022" is not included as shown in the red background cell. But, I'm worried that you might have miscopied. So, I proposed the above sample script. If you want to except for the value of the specific date, please tell me. This can be also achieved.
Reference:
Custom Functions in Google Sheets
The result that you are looking for could be achieved by using Google Sheets built-in functions in a formula:
=ARRAYFORMULA(QUERY(SPLIT(FLATTEN(Data!A4:A20&"💣"&Data!B3:F3&"💣"&Data!B4:F20),"💣"),"SELECT Col1,Col2 WHERE Col3 = 'John Doe'")
Briefly, the above formula uses FLATTEN and Google Sheets array handling feature to "unpivot" your double entry table, then uses QUERY to filter and limit the data to be returned.
Related
How do you create a "reverse pivot" in Google Sheets?

Updating Google Sheet with WooCommerce Order

I need to be able to automatically update a google sheet file every time an order is placed through WooCommerce.
I've found the solution below, but using this each individual item ordered is listed as a new row. I'd like the order to be grouped under the order number and the item quantities separated into appropriate columns instead.
https://www.tychesoftwares.com/export-woocommerce-orders-to-google-sheets-in-realtime/
Below is a Google Sheet we are manually updating at present to show you what i mean.
Example
Is there a way to send the WooCommerce orders directly through to Google Sheets in this format?
Thanks so much in advance for any advice!
Yes it looks possible.
I know nothing about WooCommerce, but I believe you can sort out the received data in any way you want.
Look, the last line in their script appends the received data as a new row:
sheet.appendRow([timestamp,order_number,order_created,order_status]);
As far as I can see, the data contains the four elements:
timestamp
order_number
order_created
orders_status
Instead, you can put these elements into any cell on your table. Something like this, for example:
var ss = Spreadsheet.GetActiveSheet();
ss.getRange('A10').setValue(timestamp); // timestamp goes to A10
ss.getRange('B20').setValue(order_number); // order_number goes to B20
ss.getRange('C30').setValue(order_created + order_status); // created + status go to C30
The same way you can add any of these elements to some existing value in some cell, etc. For example:
var old_value = ss.getRange('A2').getValue(); // get value from the cell A2
var new_value = old_value + order_number; // add with order_number
ss.getRange('A2').setValue(new_value); // put the sum back into the cell A2
The main problem is up to you. You have to figure out:
what exactly the elements you're receiving (number, names)
how exactly you want to sort them out (what to add to what... what to put where... etc)
I can't understand it from the example picture.
Here is some reference documentation on Apps Script:
Main Page - Introducing Apps Script.
Sheets Guide - Introduction to Sheets with Apps Script.
Sheets Reference - Where you will find all the details of everything you can do with Sheets in Apps Script.
Remove Duplicate Rows - A good small tutorial that will teach you the basics of Sheets and Ranges and how to manipulate them.
To export all my WooCommerce orders on a scheduled basis, I used a ready-made solution.
I used a WooCommerce API and JSON client. It worked smoothly: I got the WooCommerce API, and the JSON client was implemented in the tool already.
You just need to choose endpoint in the JSON client to get the required data. I exported all orders once a month, so I used the base URL http:// mydomain /wp-json/wc/v3/orders and my endpoint was orders.
You can check this article to understand better how it works for your purpose.
And here is WooCommerce API documentation.
I assume that setting up an export through the Apps Script is more flexible (and based on the answer above, it's working indeed), but I'm not a code guy. So I searched for an easier solution, and the API + JSON client helped.
Hope you'll find it helpful.
I would like to suggest using WooCommerce Google Sheet Plugin

How can I automate COUNTIF formulas across multiple Google sheets?

Each release, a number of my reports help test for our engineering team, they are assigned cases in a google sheet and work through it.
Is there a way i can count the amount of times their name appears in a google sheet, from a separate sheet or app?
I know i could COUNTIF, but this would mean each week I'd have to go in, and write a bunch of countif formulas for the various people testing.
I was thinking there must be a way to write a script that searches for unique names in a column, then automatically writes the countif statements and prints them to a CSV or seperate sheet, but this is really the first thing I've tried to automate and am struggling to find the right info to get started, any direction or help would be greatly appreciated.
You can use the =QUERY() Google Sheets function along with row concatenation. As an example, having a worksheet that has 3 sheets (named respectively Part1, Part2 and Part3) each of one having an issue column and an agent name column:
=QUERY({Part1!A2:B;Part2!A2:B;Part3!A2:B}, "SELECT Col2, COUNT(Col2) WHERE Col2 != '' GROUP BY Col2 LABEL Col2 'Agent', COUNT(Col2) 'Cases this release'")
Example
Result
You can see a working example of this feature in this public worksheet: https://docs.google.com/spreadsheets/d/1hrIMGsvSYOxHDoDCZNdYflE7PLh8Q_MOaeJBnr52tb8/edit?usp=sharing

Pivot Table in Adwords Script Alernative

Manipulating Pivot table in Google Adwords Script is not yet supported. Is there any script or project alternative for this?
You can generate a new tab, and insert in any cell formula with a Google Query like that:
=QUERY(IMPORTRANGE("1fSdx7f3rg_Vp_11yFuqKZmHraqFit8A", "Headline1!A1:J"), "select Col1, sum(Col4), sum(Col5), sum(Col7), sum(Col8) group by Col1", 1)
, where you specify the source of the data, the query and a headers parameter.
Note, that the columns should be named like this: Col1,.Col2 etc. So the columns order should be strict (if you want to generate a report regularly).
Google Visualization API Query Language (used in the "query" parameter) is almost the same as SQL, but with some limitations on commands that can be used.

Use existing spreadsheet formulas in a custom formula in google docs/spreadsheets

I like writing my own formulas inside of Google Docs Spreadsheets. But often what I want to do is very similar to a function that already exists. As an example, I couldn't find a function to turn a date (31-Aug-2010) into the lexical day of the week (Tuesday). I'd like to write:
=LexWeekDay('31-Aug-2010')
'Tuesday'
Clearly I can write all of this logic using core javascript, but there already exists a normal spreadsheet function called WEEKDAY() which takes a date and converts into into a number representing the day of the week [0 => Sunday, 1=> Monday, etc].
How can I access this function (or generally any function), that speadsheets already define, from my custom script?
I asked the same question at Google help, but did not get a solution. According to user Ahab:
I understand the need. I voiced the
same in the GAS help forum 1 very
early one when GAS became available
but the reaction from the GAS team was
not very promising... :( In essence
we'd need a GAS class that contains
the spreadsheet functions do allow
using them.
Note that in general spreadsheet
functions already virtually can be
used as a functional programming
language without the need of scripting
them because of high-level functions
like ArrayFormula, FILTER, SORT,
UNIQUE, etc.. Unfortunately it is not
possible to create e.g. substitution
macro's that would allow us to quickly
re-use formulas like (in pseudo-macro
format):
Name: INVERSE Description: Inverse a
columnar array Syntax: #INVERSE( array
) Call: #INVERSE( #1 ) Execute:
=ARRAYFORMULA(SORT( #1 ; ROW( #1 ); FALSE))
In your custom appscript, you can use the in-built formulas of google spreadsheet in this way:
Lets say you want to use =WEEKDAY() function on cell A1.
Then, get your active spreadsheet like this in your custom appscript function:
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("YOUR_SHEET_NAME");
now, set the formula like this:
sheet.getRange("A1").setValue("=WEEKDAY()");
Also, if you want to convert 0,1 etc to Sunday,Monday...then define an array like this:
var days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
And then use:
var dayIndex = sheet.getRange("A1").getValue();
Logger.log(days[dayIndex]);
You can see the logs using ctrl+enter or by going to View->Logs in script editor itself.