Google Spreadsheet Populating Cells in Other Sheet Based on Value - google-apps-script

Am new to Google Docs, but have to create a cumulative report of comments that are flagged as positive or negative. I have 6 worksheets that ideally would populate to a single report, but I could create 6 individual reports for now.
In the source sheet, ColA is a numeric code identifying the category. Col B is the category description; Col C are the notes from one person; Col D is the code to identify it as positive or negative; Cols E and F are the notes from a 2nd person; G/H from a 3rd, etc.
The report sheet needs to transpose the vertical comments by category with the positive comments for all persons for the first category in Col G, the negative comments for the 1st category in Col H, etc for all 6 categories.
I was able to manually create this report using the following formula to extract the Positive comments from column C:
QUERY(EntrySheet1!C5:D15;"select * where D='P'")
But, it's pretty tedious to copy the formula laterally and vertically to accommodate all 6 categories and all 6 note takers.
So, my questions are whether or not there is an easier way to extract the information the way I need to report it. Also, is there a way to use something like Excel's Indirect function where I could use the concatenate function to build the formulas and the Indirect to evaluate that function. My thought here is that I could have an entry cell where I would identify which cumulative report I wanted to view by simply updating the cell. An alternative would be to load the data into an array and use a script to populate a static cumulative report. Real-time updating with formulas would be ideal, but creating a static report that is created from a script is acceptable. My biggest concern is the manual effort to update the formulas since they are sheet specific.

Use Google Spreadsheet INDIRECT function.
See the Google spreadsheets function list:
INDIRECT(reference)
Returns the reference specified by a text string. This function can also be used to
return the area of a corresponding string. Reference is a reference to a cell or an
area (in text form) for which to return the contents.
You might be able to feed the results of indirect into your query.

Related

How to count unique values that are present in 2 different sheets only if they exist in both sheets

[Goal]
I want to be able to count unique values that are present in 2 different sheets only if they exist in both sheets.
[Details]
First, there are 2 sample data sheets (Data A, Data B) within the same Spreadsheet and it also has a sample dashboard to do the calculations. One thing to note about the data sheets is that they have different ranges, so they have different number of columns and rows. However, a couple things they have in common are the Month and ID columns.
Next, in the Dashboard sheet, there are 3 cells where B3 is the Month selector, C3 is to count the number of unique IDs that are included in both sheets (Data A & Data B) based on the month. With D3, I would like to count the number of unique IDs that are included in both sheets (Data A & Data B) where the the Month are the same AND Data B sheet's Cumulative column is 1.
[What I tried so far]
I tried using the COUNTUNIQUEIFS function and had the range as an array (by using the curly bracket) in the below way, however, it didn't work.
=COUNTUNIQUEIFS('Data A'!$B:$B,'Data A'!$A:$A,B3,'Data B'!$A:$A,B3)
I also tried without making the range argument an array.
=COUNTUNIQUEIFS('Data A'!$B:$B,'Data B'!$A:$A,B3)
Both attempts results in 1 for February 2023 when it should return 2. The weird thing is that January 2023 should return 3 and it correctly returns 3.
Hope someone can help me out with this. If there's a more elegant solution to achieve this by using Google Apps Scripts, I'd like to see hear about that as well.
You can try filtering both ranges for month, and the FILTER again by comparing them with MATCH and counting the remaining results:
=LAMBDA(ar,br,COUNTA(IFERROR(FILTER(ar,NOT(ISERROR (MATCH(ar,br,0))))))
(FILTER('Data A'!B:B,'Data )A'!A:A=B3),FILTER('Data B'!B:B,'Data B'!A:A=B3))
And just add an additional filter for the next column and the cumulative =1 'Data B'!C:C=1
=LAMBDA(ar,br,COUNTA(IFERROR(FILTER(ar,NOT(ISERROR (MATCH(ar,br,0)))))) (FILTER('Data A'!B:B,'Data )A'!A:A=B3),FILTER('Data B'!B:B,'Data B'!A:A=B3,'Data B'!C:C=1))

Can I show the results of COUNTIF in one column only if there is data in another column?

I have a spreadsheet with multiple sheets.
Sheet A is generated from a template, and it is where users will enter in data to be formatted into a report; it will be deleted after that report is submitted.
As people enter info into Column A of Sheet A, they don't have to enter client information if we already have them entered in this spreadsheet, but otherwise they need to go over to Sheet B and enter it in.
To make it easier for them (so they don't have to check every time, or go back and enter info later after getting an error generating the report), I have used conditional formatting. The way it works is, column Z is set up as a helper column, and uses a "COUNTIF" function to check if the client ID in Sheet A, Column A is found in Sheet B, Column C. Sheet A Column Z returns 0 or 1 (or, theoretically, more than one if we had duplicates), and then Sheet A column A has conditional formatting based on Column Z's value-- if the client is already in, the cell for client ID turns green after they type it; if not, it turns red.
It works great! However, I am adding scripts to these sheets, and looping through them. This helper column is filled from Z1 to Z1000, which means I can't use sheet.maxRow() to get the last row.
I see plenty of workarounds on the script side, but I was wondering if anyone has a clever way to input a value into the helper column Z ONLY IF the corresponding cell (same row) in column A has a value using spreadsheet formulas.
I suspect that an array formula with a filter might do it, but I have little experience with either and can't get anything to work out.
Thanks for your help!
You can use this expression with INDEX, MAX and ROW to make an ARRAYFORMULA only expandable until the last cell with value in column:
A2:INDEX(A2:A,MAX(ROW(A2:A)*(A2:A<>"")))
It will go from A2 to the maximum number of row in A in which A is different than null (that's why both conditions are multiplied).
Then you can set a formula like this in Z2 (check the ranges in case something is not right from reading your text, and delete all other formulas in Z too in case you weren't using an arrayformula already):
=BYROW(A2:INDEX(A2:A,MAX(ROW(A2:A)*(A2:A<>""))),LAMBDA(each,IF(each="","",COUNTIF('Sheet B'!C:C,each))))

Google script custom function for different column [duplicate]

I'm trying to do a couple of different things with a spreadsheet in Google and running into some problems with the formulas I am using. I'm hoping someone might be able to direct me to a better solution or be able to correct the current issue I'm having.
First off all, here is a view of the data on Sheet 1 that I am pulling from:
Example Spreadsheet
The first task I'm trying to accomplish is to create a sheet that lists all of these shift days with the date in one column and the subject ("P: Ben" or S: Nicole") in another column. This sheet would be used to import the data via a CSV into our calendar system each month. I tried doing an Index-Match where it used the date to pull the associated values however I found that I had to keep adjusting the formula offsets in order to capture new information. It doesn't seem like Index-Match works when multiple rows/columns are involved. Is there a better way to pull this information?
The second task I am trying to accomplish is to create a new tab which lists all the dates a specific person is assigned too (that way this tab will update in real time and everyone can just look at their own sheet to see what days they are on-call). However, I run into the same problem here because for each new row I have to change the formula to reflect the correct information otherwise it doesn't pull the correct cell when it finds a match.
I would appreciate any and all information/advice on how to accomplish these tasks with the formula combination I mentioned or suggestions on other formulas to use that I have not been able to find.
Thanks in advance!
Brandon. There are a few ways to attack your tasks, but looking at the structure of your data, I would use curly brackets {} to create arrays. Here is an excerpt of how Google explains arrays in Sheets:
You can also create your own arrays in a formula in your spreadsheet
by using brackets { }. The brackets allow you to group together
values, while you use the following punctuation to determine which
order the values are displayed in:
Commas: Separate columns to help you write a row of data in an array.
For example, ={1, 2} would place the number 1 in the first cell and
the number 2 in the cell to the right in a new column.
Semicolons: Separate rows to help you write a column of data in an array. For
example, ={1; 2} would place the number 1 in the first cell and the
number 2 in the cell below in a new row.
Note: For countries that use
commas as decimal separators (for example €1,00), commas would be
replaced by backslashes () when creating arrays.
You can join multiple ranges into one continuous range using this same
punctuation. For example, to combine values from A1-A10 with the
values from D1-D10, you can use the following formula to create a
range in a continuous column: ={A1:A10; D1:D10}
Knowing that, here's a sample sheet of your data.
First Task:
create a sheet that lists all of these shift days with the date in one
column and the subject ("P: Ben" or S: Nicole") in another column.
To organize dates and subjects into discrete arrays, we'll collect them using curly brackets...
Dates: {A3:G3,A7:G7,A11:G11,A15:G15}
Subjects: {A4:G4,A5:G5,A8:G8,A9:G9,A12:G12,A13:G13,A16:G16,A17:G17}
This actually produces two rows rather than columns, but we'll deal with that in a minute. You'll note that, because there are two subjects per every one date, we need to effectively double each date captured.
Dates: {A3:G3,A3:G3,A7:G7,A7:G7,A11:G11,A11:G11,A15:G15,A15:G15}
Subjects: {A4:G4,A5:G5,A8:G8,A9:G9,A12:G12,A13:G13,A16:G16,A17:G17}
Still with me? If so, all that's left is to (a) turn these two rows into two columns using the TRANSPOSE function, (b) combine our two columns using another pair of curly brackets and a semicolon and (c) add a SORT function to list the dates in chronological order...
=SORT(TRANSPOSE({{A3:G3,A3:G3,A7:G7,A7:G7,A11:G11,A11:G11,A15:G15,A15:G15};{A4:G4,A5:G5,A8:G8,A9:G9,A12:G12,A13:G13,A16:G16,A17:G17}}),1,TRUE)
Second Task:
create a new tab which lists all the dates a specific person is
assigned too (that way this tab will update in real time and everyone
can just look at their own sheet to see what days they are on-call).
Assuming the two-column array we just created lives in A2:B53 on a new sheet called "Shifts," then we can use the FILTER function and SEARCH based on each name. The formula at the top of Ben's sheet would look like this:
=FILTER(Shifts!A2:B53,SEARCH("Ben",Shifts!B2:B53))
Hopefully this helps, but please let me know if I've misinterpreted anything. Cheers.

Is there a way in google sheets to select a list of cells as an array to be used as a parameter in a connected sheet?

I have a new google sheet set up to query my database via a connected sheet.
The query returns a list of our shops and their sales per year. Each shop has an ID.
I am able to set Cell A1 in another, reference sheet, to be a parameter in the query. This way the connected query only returns results for that particular store ID.
When using this, I really want to put an IN function into my query. The connected query would then look something like.
SELECT * FROM shops where shops.id in (#RANGE)
And #RANGE would be A2:A as an array.
I've had success naming each cell as a new parameter and then:
SELECT * FROM shops where shops.id in (#REFERENCE1, #REFERENCE2)
Is there a more elegant solution?
Maybe a little late, but the easiest way I found was to convert to regex.
select (#POSTCODES) as test, postcode
from `postcode.au_towns`
where regexp_contains(#postcodes,safe_cast(postcode as string))
Where #POSTCODES is a gsheet string using a formula like join("|",UNIQUE(Sheet1!D2:D)).
Just make sure to remove the extra "|" generated using something like
left(B2,len(B2)-1)
This might work for you.
=SUBSTITUTE(QUERY(FILTER(D3:D,D3:D<>"",E3:E),"WHERE Col1 <> ''",9^99)," ","|")
This filters a column of store IDs based on which ones have been selected, and coverts that into a text string similar to the query you have been using. Producing something like "A1|A3|A7".
The query then just points to that result for the contains criteria.
Note that if your range of store IDs to report on is built in some other fashion, you just need to point to its range, instead of using the filter I have.
See a sample sheet here. This also shows a merged example of the two formulas, to produce the report all from one formula.
https://docs.google.com/spreadsheets/d/11uMa7CNcTXBnnpWGSIC_WvGSa-P2GTLQ2T7GvTgY4oM/edit?usp=sharing
Let us know if this helps you.
=QUERY(IMPORTRANGE("Google_Sheet_ID_Can_Be_Find_In_URL", "Sheet_Name!Range(you want to query)"),"SELECT * ")
or
=QUERY(IMPORTRANGE("Google_Sheet_ID_Can_Be_Find_In_URL", "Sheet_Name!A2:A"),"SELECT * ")
or
=QUERY(IMPORTRANGE("Google_Sheet_ID_Can_Be_Find_In_URL", "Sheet_Name!Range"),"SELECT * WHERE Col2='shops.id'")")
IMPORTRANGE() method import data from another worksheet. In the parameter, you type google sheet id from the url with quotes, type the desired sheet name end with ! Then you type the range from that sheet you want to query. When you wrap it with the outer QUERY() method, you can query the data from that range such as A2:A by selecting specific columns including the column with the range or * from that sheet name
When you're using IMPORTRANGE() method, it's going to return an array. The selected columns have to label in numeric like "SELECT Col 1, Col 2, Col 3"

Script to randomly pick from a list if cells match specific value

Looking for a basic script that will trigger if cell A1 AND B1 contain a specific text, it will return a value (name) from a random pool of entries and display it in cell C1. My goal is to create a chart, pick to values in A and B and depending if specific values match, pick a random entry from a list and display it in C.
I was trying RANDBETWEEN + CHOOSE which technically works, but every other action in the spreadsheet will automatically generate a new random and re-trigger all the randoms, altering the whole list (since it's volatile) which I don’t want to happen, I’m open to suggestions from any other formulas that might work.
Thanks a lot.
There is a way to restrict re-evaluation of random functions only when specific cells are edited. Namely:
Create another spreadsheet, call it S2 to distinguish from the original spreadsheet A1
In S2, enter importrange referring to a cell or range of spreadsheet S1
Also in S2, enter any random number formulas you need: rand, randbetween, etc.
Back in S1, enter importrange that imports the output of those random formulas.
Result: the random values will get re-calculated only when the range of S1 in item 2 changes. Entering data elsewhere in S2 will not trigger recalc.
A script is a possible solution, but takes more work: you'd need to use the onEdit trigger to run a function on every edit; the function would need to check if the edit
Custom functions are only recalculated when their arguments change. You could use this feature to prevent that the result changes.
To force a recalculation you could
Delete and reenter the formula
Use a control argument that you changes every time that you want that the formula result be recalculated.