How can I automate COUNTIF formulas across multiple Google sheets? - google-apps-script

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

Related

Google Apps Script - When new row containing data with specific keywords is added to Sheet 1, move that to a new row in a new corresponding sheet

I am using Google Sheets to evaluate data from a Zoho Form. I would like to sort the raw data from spreadsheet 1 ('Raw Data') into 3 new spreadsheets depending on 2 specific keywords found in 2 different columns in 'Raw Data'.
For context - the keywords for the first column (column 'G') are:
Ordered
Stock
Preordered
the keywords for the second column (column 'F') are:
B2B
B2C
There are a total of 6 possibilites that need to be accounted for: ordered & B2B, ordered & B2C, stock & B2B, stock & B2C, preordered & B2B, preordered & B2C.
If for instance a form is submitted for 'Ordered' and 'B2B', then a specific succession of rows must be transferred to the corresponding 'Ordered' spreadsheet because of Zoho Forms' nature of staggering the submitted information horizontally in the 'Raw Data' sheet. These rows will change depending on which one of the 6 combinations is chosen in the Form.
The 3 new spreadsheets will be named according to the keywords found in column 'G'.
So far I have been working with a Query in the new sheets to pull the needed information from the 'Raw Data' spreadsheet, however this hasn't proven to work as intended as Zoho Forms creates a new row rather than filling an existing one, causing the query to skip the newly created row and therefore not pulling any data.
Here is the Query, maybe it'll help identify what I am looking for:
=IF('Raw Data'!G6="Ordered", IF('Raw Data'!F6="B2B",QUERY('Raw Data'!A6:DN6,"SELECT A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T ORDER BY C desc LIMIT 1"), QUERY('Raw Data'!A6:DN6,"SELECT A,B,C,D,E,F,G,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AS,AT,AU ORDER BY C desc LIMIT 1")))
I have found someone who posted a Script similar to what I am looking for, however it is missing that conditional aspect to it. Here is the script, maybe it can serve as a good starting point. (all credit for this code goes to Mike Steelson):
function moveData() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var rng = ss.getSheetByName('Sheet1').getRange('A2:C2')
ss.getSheetByName('Sheet2').getRange(ss.getSheetByName('Sheet2').getLastRow()+1,1,1,3).setValues(rng.getValues())
rng.clearContent()
}
I am quite new to building these sort of things so please forgive me if the Query and my overall explanation isn't the best, if you have any questions I'll try my best to elaborate!
Cheers,
Rupert.

Copy Adjacent Cells alongside Duplicate Cells

I have a very large Google Sheet spreadsheet that I need help with.
I have a long list of Network Switches that are very often repeated that I am trying to automatically copy the associated SKU into a separate adjacent cell.
My goal was, once the SKU is added the first time, whenever the same switch is added again, it will autopopulate with the same SKU.
For instance, C2461:C2463 are repeated, and once K2461 is populated, would like K2462 & K2463 to follow suit.
Any help would be greatly appreciated!
You can try this formula on Column L (col L will serve as a helper column):
=iferror(arrayformula(VLOOKUP(C2:C,C2:K,9,False)),"")
For now I can't seem to fit the formula without the use of a helper column (so I created a separate sheet for now that will serve as a database for the VLOOKUP formula) but this should get you started.
Sample using a helper spreadsheet (Database):
=iferror(arrayformula(VLOOKUP(Database!A2:A,Database!A2:B,2,False)),"")
Output:

Sum by products horizontally into vertical data Google Sheets

I'm using Google Sheets to collect data of daily arrivals of products. My data looks as shown below:
What I'm trying to achieve is a sum by product:
I've tried something with a Script but with not much luck because I'm a little lost. Is there a way to do this through formulas? Or would it be easier using Scripts/Macros?
Thanks for any help you may provide!
This can be done with native google sheet formula's. Change ALL the A1:D3 to your range. Leave out the headers (row 1) and the ID (column A). So start at B2. I don't understand the ID column. Does not seem to do something?
The formula:
=QUERY({
FILTER(FLATTEN(A1:D3),ISTEXT(FLATTEN(A1:D3))),
FILTER(FLATTEN(A1:D3),ISNUMBER(FLATTEN(A1:D3)))},
"SELECT Col1, SUM(Col2) GROUP BY Col1 LABEL Col1 'Products', SUM(Col2) 'KG'",0)
So FLATTEN will create a list like this:
Snack
4
General
6
We filter out all the text and all the number, then this is the input data for the query. TIP: Copy the formula's out the main formula and see what it does.
If I'm understanding your post correctly, you have an ID column followed by 40 columns which alternate "product ... kg ... product ... kg ..." for a total of 41 columns running from A to AO.
I don't know the name of your source-data sheet. So I'll just call it "Source Sheet" in my formula. Change that throughout to your actual source-data sheet name.
You will want this formula in a separate sheet: not the source-data sheet:
=ArrayFormula({"ID","PROD","KG";QUERY(SPLIT(FLATTEN(FILTER('Source Sheet'!A2:A,'Source Sheet'!A2:A<>"")&"|"&FILTER('Source Sheet'!B2:AO,ISEVEN(COLUMN('Source Sheet'!B2:AO2)))&"|"&FILTER('Source Sheet'!B2:AO,ISODD(COLUMN('Source Sheet'!B2:AO2)))),"|",0,0),"Select * Where Col2 Is Not Null")})
Before I invest time explaining how it works, please test it out and report back whether this formula produces the desired result. If so, I'll explain the workings of it.

How to create INDIRECT array string of multiple sheet references in Google Sheets?

I am attempting to use a query to display data off multiple Google Sheets. I make a new sheet every week that has a specific sheet name, e.g. Week of 01/13, Week of 01/06 and so forth.
The following is where my idea spawned from for reference:
I have a summary sheet that is using COUNTA(INDIRECT("'" & A5 &
"'!E4:E",true)
A5 being a cell that concatenates a date and words to replicate the
sheet names.
The row on the summary sheet does not populate until B5<=today()
So I am able to set it an forget it and the sheet will continue to
give me my weekly data as the days progress and keeps the sheets clean
until the week is upon us.
Long story short, I have a query that I use that gives me all the data I need with a specific parameter but I have to manually update the data syntax array with the new sheet names each week.
=QUERY({'Week of 01/13'!A:P;'Week of 01/06'!A:P;'Week of 12/30'!A:P;'Week of 12/23'!A:P;'WEEK OF 12/16'!A:P;'WEEK OF 12/09'!A:P;'WEEK OF 12/02'!A:P;'WEEK OF 11/25'!A:P;'WEEK OF 11/18'!A:P;'WEEK OF 11/11'!A:P;'WEEK OF 11/04'!A:P;'WEEK OF 10/28'!A:P;'WEEK OF 10/21'!A:P;'WEEK OF 10/14'!A:P;'WEEK OF 10/07'!A:P;'WEEK OF 09/30'!A:P;'WEEK OF 09/23'!A:P;'WEEK OF 09/16'!A:P;'WEEK OF 09/09'!A:P;'WEEK OF 09/02'!A:P},
"Select * where Col11 = 'RD' order by Col2 desc",0)
I would like to build a reference to an array that will auto-populate a concatenation based on the day.
Using the following code I can have the concatenate give me the array I need,
=if(H4<=today(),CONCATENATE("'",H$1,text(H4,"mm/dd"),"'!A:P;",),"")
but when I try to input it into the query function it just returns the concatenated text:
=QUERY(I1,"Select *")
'Week of 01/06'!A:P;'Week of 01/13'!A:P
I have tried with and without the curly brackets with no success.
I would like the sheet to be able to refresh and see that it is the correct day, the new sheet name is populated and the query gets updated.
I need help with making I1 work.
Link to Test Query Sheet
dudes who copy-pasted INDIRECT function into Google Sheets completely failed to understand the potential of it and therefore they made zero effort to improve upon it and cover the obvious logic which is crucial in this age of arrays.
in other words, INDIRECT can't intake more than one array:
=INDIRECT("Sheet1!A:B"; "Sheet2!A:B")
nor convert an arrayed string into active reference, which means that any attempt of concatenation is also futile:
=INDIRECT(MasterSheet!A1:A10)
————————————————————————————————————————————————————————————————————————————————————
=INDIRECT("{Sheet1!A:B; Sheet2!A:B}")
————————————————————————————————————————————————————————————————————————————————————
={INDIRECT("Sheet1!A:B"; "Sheet2!A:B")}
————————————————————————————————————————————————————————————————————————————————————
=INDIRECT("{INDIRECT("Sheet1!A:B"); INDIRECT("Sheet2!A:B")}")
the only possible way is to use INDIRECT for each end every range like:
={INDIRECT("Sheet1!A:B"); INDIRECT("Sheet2!A:B")}
which means that the best you can do is to pre-program your array like this if only part of the sheets/tabs is existant (let's have a scenario where only 2 sheets are created from a total of 4):
=QUERY(
{IFERROR(INDIRECT("Sheet1!A1:B5"), {"",""});
IFERROR(INDIRECT("Sheet2!A1:B5"), {"",""});
IFERROR(INDIRECT("Sheet3!A1:B5"), {"",""});
IFERROR(INDIRECT("Sheet4!A1:B5"), {"",""})},
"where Col1 is not null", 0)
so, even if sheet names are predictable (which not always are) to pre-program 100+ sheets like this would be painful (even if there are various sneaky ways how to write such formula under 30 seconds)
an alternative would be to use a script to convert string and inject it as the formula
A1 would be formula that treates a string that looks like real formula:
=ARRAYFORMULA("=QUERY({"&TEXTJOIN("; ", 1,
IF(A3:A<>"", "'Week of "&LEFT(A3:A, 5)&"'!A1:D5", ))&
"}, ""where Col1 is not null"", 1)")
further populating of A6:A will expand the string automatically
then this script will take the string from A1 cell and it will paste it as valid formula into C5 cell:
function onEdit() {
var sheet = SpreadsheetApp.getActive().getSheetByName('Master Sheet');
var src = sheet.getRange("A1");
var str = src.getValue();
var cell = sheet.getRange("C5");
cell.setFormula(str);
}
of course, the script can be changed to onOpen trigger or with custom name triggered from the custom menu or via button (however it's not possible to use the custom function as formula directly)
If you're trying to update the data your query is looking at and you're feeding it a string, you need to put that string within the indirect() function. That will interpret your string as a data reference and point your query() in the right direction.
So for this you'd probably have
=QUERY(INDIRECT(I1),"Select *")

use JOIN to pull multiple IMPORTRANGES into SORT(ARRAYFORMULA({importrange1; importrange2; etc}

How can I use JOIN (and maybe VLOOKUP? FILTER?) to make a list of IMPORTRANGES, resulting in something like {IMPORTRANGE(C3,$E$1); IMPORTRANGE(C4,$E$1); IMPORTRANGE(C5,$E$1); IMPORTRANGE...}?
Currently, in a google sheet, I have a formula that looks like this: =SORT(ARRAYFORMULA({IMPORTRANGE(C3,$E$1);IMPORTRANGE(C4,$E$1);IMPORTRANGE(C5,$E$1);IMPORTRANGE..." where spreadsheet urls are in Col C and a range (same for every imported sheet) is in E1.
Typing it all in was fine when I only had about a dozen spreadsheets I was importing and they all already existed. But now I want to import many more spreadsheets (I heard that the limit of 50 importranges no longer applies) and they don't all exist yet. If I keep things as they are, every time I add another spreadsheet url to Column C, I'll also have to go in and edit my =SORT formula.
Then I found this thread, Fill ArrayFormula with dynamic ImportRange, which has a suggested answer listed as: ="=sort(ARRAYFORMULA({"&JOIN(";",ArrayFormula("IMPORTRANGE("""&VLOOKUP(FILTER(G2:G20,G2:G20<>""),Sheet3!$A$2:$B,2,0)&""","""&G1&"!A2:B"")"))&"}),1,True,2,True)"
The JOIN in there looks intriguing (I just recently learned about JOIN) but I don't understand all the syntax (like """) and I also can't access to original spreadsheet to see what the references point to.
So, I'm looking for help in how to input the C3, C4, C5, etc into the JOIN -- not sure how the VLOOKUP helps me -- and also if anyone knows why there are so many ="&=&"""s throughout the suggested formula...
One of the solutions below may do what you need. The first is what you requested. The second is the one which will probably work to combine multiple IMPORTRANGE formulas.
SOLUTION 1
="="&ArrayFormula(REGEXREPLACE(QUERY(UNIQUE(TRANSPOSE(SPLIT(CONCATENATE(IF(E3:E="","","IMPORTRANGE("&E3:E&", $E$1)"&":")),":"))),,9^99),"\)(.*?)I","\), I"))
SOLUTION 2
="=QUERY({"&ArrayFormula(REGEXREPLACE(QUERY(UNIQUE(TRANSPOSE(SPLIT(CONCATENATE(IF(E3:E="","","IMPORTRANGE("&E3:E&", $E$1)"&":")),":"))),,9^99),"\)(.*?)I","\); I")&"},""Select Col1 where Col1<>''"",0)")
You would then just copy the cell, select the destination cell and "paste as values" into the formula bar.
You can see the sheet in action HERE (just make a copy of it to use).