Dynamically Updating Formula Based on a Cell Reference - google-sheets

In one of my projects I am using the following code:
(The queries are left blank as what they look for is not the issue.)
=UNIQUE({QUERY(1);Query(2)})
What I want to be able todo, is have a user enter a number into a cell and based on number that it would add more queries the to formula. So if the user put in the number 5 it would be;
=UNIQUE({QUERY(1);QUERY(2);QUERY(3):QUERY(4);QUERY(5)})
I want to do this in a formula and only use AppScript as a last resort.
Is this even possible to-do?

Prepopulate all the queries, and omit some IF the input number isn't high enough.
=UNIQUE({
IF(H1<1,"",QUERY(A1:E5,"select A where A is not null"));
IF(H1<2,"",QUERY(A1:E5,"select B where B is not null"));
IF(H1<3,"",QUERY(A1:E5,"select C where C is not null"));
IF(H1<4,"",QUERY(A1:E5,"select D where D is not null"));
IF(H1<5,"",QUERY(A1:E5,"select E where E is not null"))
})

Related

Google Sheets: Determine the percentage of times that Values B-E appear in a row if Value A is the first value in the row

I am trying to determine how often values appear in a row based on the lead value of the row. Essentially, if "A" is the first value of the row, what percentage of those "A" rows contain the value "B" in the subsequent columns, what percentage contain "C" in subsequent columns, etc.
Below is an example table with the leads and their partners
Lead
Partner 1
Partner 2
A
B
C
A
C
E
B
A
E
C
B
A
A
D
B
B
C
E
A
B
D
B
E
D
C
D
B
A
E
C
I want to output a table which stays what percentages of times values B-E appear for rows which start with A. In the example above, A is the lead 5 times, and B appears in those A rows 3 times, so the value is 60%
A Partners:
Value
%
B
60%
C
60%
D
40%
E
40%
Partners will always be unique, i.e. the same value wont appear in both columns 2 and 3 (e.g. no "BEE"). It doesn't matter which column the partner appears in (2 or 3), it only matters if they appear in either column after where A is the lead.
I plan to have multiple "Partner tables" like the solution above, so I can also see how many times A&C-E appear in B-led rows, etc. But once I know how to make one table I can then make the others.
I tried a combination of IF and COUNTIF formulas, basically trying to say
If A2 contains A, then count the number of times B appears in the subsequent columns and divide it by the number of times A is in the lead.
=If((A2="A"),((COUNTIF(B2:C11,"B")/COUNTIF(A2:A11,"A")),0)
This of course results in skewed results because it counts how many times B appears in all rows, not just the ones which are lead by A. I'm having trouble limiting the count of Bs to only A rows.
Thank you!
You can set this formula:
=COUNTIF(FILTER(B:C,A:A = $F$1),F2)/COUNTA(FILTER(A:A,A:A = $F$1))
Or with BYROW for the four (or all you need) rows:
=BYROW(F2:F5,LAMBDA(each,COUNTIF(FILTER(B:C,A:A = $F$1),each)/COUNTA(FILTER(A:A,A:A = $F$1))))

Dynamic query formula nested inside an array

I have a query formula in Google sheets that updates based on additional columns of data in my Google Sheet seen here =QUERY('Deals List - URL Split'!A:DZ, "select A, C where C contains 'http'",)
So it may add QUERY('Deals List - URL Split'!A:DZ, "select A, E where E contains 'http'",)and then it will end up becoming the below and so on for each additional.
=QUERY('Deals List - URL Split'!A:DZ, "select A, C where C contains 'http'",);QUERY('Deals List - URL Split'!A:DZ, "select A, E where E contains 'http'",)
What I am trying to do is have the resultant query formula which is in cell 'List'!A1 as QUERY('Deals List - URL Split'!A:DZ, "select A, C where C contains 'http'",);QUERY('Deals List - URL Split'!A:DZ, "select A, E where E contains 'http'",) be used in an array formula as a reference so I don't have to update the formula each time a new query formula is added.
The static query formula is
=SORT(ARRAYFORMULA({QUERY('Deals List - URL Split'!A:DZ, "select A, C where C contains 'http'",);QUERY('Deals List - URL Split'!A:DZ, "select A, E where E contains 'http'",)}),1,TRUE,2,TRUE)
and indeally the one that gets the dynamic formula would be like below but I always get an error and get just the literal static formula above.
=SORT(ARRAYFORMULA({'List'!A1}),1,TRUE,2,TRUE)
I think I have an answer (or two) for you. After looking at your sheet, I have to say that I am sure that a simpler design is possible for your sheets, that would simplify everything. Anyway, I've built one formula, using only your data on sheet '2 URL SPLIT'!, and the desired columns from '4 URL FILTER'!A1:1. See my sample tab, GK-6 ITEMS AND URLS, added to your sheet.
The formula, reduced to its basic form, is:
={
IFERROR({'2 URL SPLIT'!$A$2:$A, INDIRECT(INDEX(
{ARRAYFORMULA(IFERROR("'2 URL SPLIT'!"
& TRANSPOSE('4 URL FILTER'!1:1)
& TRANSPOSE(SPLIT(
{"2:"
& TEXTJOIN("~2:",1,TRANSPOSE('4 URL FILTER'!1:1))},"~",0,0))
& ROWS('2 URL SPLIT'!A:A)))},1,0))},{"",""})
}
The formula is not truly dynamic, but it ignores blank columns. So the cheat I've used is to expand the capacity of the formula to include extra blank columns, and if they get filled with data, the data will be used. I've set it to include 50 columns of data, where you are currently using 39, but you could expand it to handle about 200 columns, before it reaches the 50,000 character limit of a cell.
The formula as shown above handles one column. For the one that handles fifty columns, as in my sample sheet, I simply duplicate the inner formula, everything inside the outer braces "{....}" and increment the number in it. You only need to do this once, or copy mine from my sheet. You do not need to update if/when your data columns expand.
I'm happy to add much more explanation if you decide that this formula works for you. But the basis of the formula is dynamically building the ranges of cells to query. The result of this inner part of the formula is shown below. Note that the 2 in each range is hard-coded, and can be changed if your structure changes, but the limit of the range is calculated from your data.
The rest of the formula uses an index into this "table", incrementing by one to select each successive data range, which adds a new column of data to be queried. These data ranges from '2 URL SPLIT!' include column A and one subsequent data column, as specified in '4 URL FILTER'!A1:A, and are stacked one above the other, by using a ";" separator.
The query is then run against this vertical, two column stack, selecting all rows where column 2 contains "http".
The final result is shown below:

Google Sheets counting with multiple criteria

I have a Google Sheet where I have several columns of data, and I want to get a count of how many rows match two criteria, where one of the criteria is matching either one of two values.
Here’s an example of the data I have:
What I want to do is things like: get a count of how many rows have “Yes” in column A, and either “A” or “C” in column B. Or how many rows are “No” and either “I” or “X”.
I’ve come up with this:
=COUNTIFS($A1:$A21,"Yes",B1:B21,"="&"A")+COUNTIFS($A1:$A21,"Yes",B1:B21,"="&"C")
…but that feels clunky, and makes it harder to update if I decide to shift columns around. Not to mention really bad if I want to combine multiple bits of information into a single cell, such as this:
=(COUNTIFS($A1:$A21,"Yes",B1:B21,"="&"A")+COUNTIFS($A1:$A21,"Yes",B1:B21,"="&"C")) & "/" & (COUNTIFS($A1:$A21,"No",B1:B21,"="&"A")+COUNTIFS($A1:$A21,"No",B1:B21,"="&"C"))
I mean, that’s just awful. It works, but it’s awful.
I’ve tried using OR() without success, and also tried curly-bracket syntax without success. I fully acknowledge I may have done both of them wrong, but if so, darned if I can figure out what I missed. Any Sheets mavens willing to take pity on an old dude and show me a much smarter way to do this?
Shortest one so far:
=SUMPRODUCT(REGEXMATCH(A1:A8&B1:B8,"(?i)Yes(A|C)"))
CONCATENATE both columns using & and use REGEX on the result.
(?i) Case insensitive
yes(A|C) yes followed by A or C
SUM up all the trues.
For a complex condition,
=ARRAYFORMULA(SUM(--REGEXMATCH(A1:A8&B1:B8,"(?i)yes(A|C)"))&"/"&SUM(--REGEXMATCH(A1:A8&B1:B8,"(?i)no(I|X)")))
Note that there should be no trailing spaces following yes/No and no leading spaces before A or C etc. If there are, use TRIM.
I would use query with variables. In F1 put:
=query(A:B,"select count(A) where A ='"&C2&"' AND B='"&D2&"' OR A ='"&C2&"' AND B='"&E2&"'")
In C2 enter "Yes" or "No" and in D2 and E2 enter the B letters (or leave blank). Enter whatever headers you want in C1, D1, and E1.
I'm not sure if this is exactly what you're looking for, but you could simplify it a bit by just creating a "pairings" list.
E2: =COUNTIFS(A:A,$C2,B:B,$D2)
E3: =COUNTIFS(A:A,$C3,B:B,$D3)
...
E6: =SUM(E2:E5)
The benefit is that it's flexible - you can add as many pairings as you want later on. Also, no complexity of array formulas.
For complex logic, use more powerful commands like query or filter.
count the rows with “Yes” in column A, and either “A” or “C” in column B.
becomes
=query(A:C, "select count(A) where A='Yes' and (B='A' or B='C')")
or
=query(A:C, "select count(A) where A='Yes' and (B='A' or B='C') label count(A) ''")
if you don't want to have a column header such as "count".
This is pretty much stating the goal in English (well, SQL version of it).
Simplify:
Create a column C that is TRUE if B is A or C, FALSE otherwise.
Create a column D that is TRUE if B is I or X, FALSE otherwise.
Create a column E that is TRUE if A is "yes" and C is TRUE.
Create a column F that is TRUE if A is "no" and D is TRUE
Create a column G that is column E or column F.
Sum up the values in column G.

Find and replace by multiple patterns

Suppose I've got a text values column (named Data), generated by =unique() function. Also, there is an array of patterns to find and replace for (Find and Replace columns).
Which formula should I use to scan each cell in Data for multiple patterns in Find and replace it, if match?
Data Find Replace Result
1 a c z a
2 b f y b
3 c e x z
4 d d
5 e x
6 c z
Tried =SUBSTITUTE() and =IF() functions, but it fails, when I set an array of patterns, instead of single one.
If the table you is in range A1:E7, try this formula
=TRANSPOSE(SPLIT(REGEXREPLACE(REGEXREPLACE(REGEXREPLACE(ARRAYFORMULA(CONCATENATE($B$2:$B$7&"|")),$C$2,$D$2),$C$3,$D$3),$C$4,$D$4),"|"))
You can read further about this in an older post and google docs forum.
Array solution
This formula takes range to replace, so it can be used for variable number of patterns:
=QUERY(ARRAYFORMULA({REGEXMATCH(A2,$B$2:$B$4),
REGEXREPLACE(A2,$B$2:$B$4,$C$2:$C$4)}),
"select Col2 order by Col1 desc limit 1")
or this one:
=INDEX(ArrayFormula(REGEXREPLACE(A2,$B$2:$B$4,$C$2:$C$4)),IFERROR(MATCH(A2,$B$2:$B$4,0),1))
or this:
=IFERROR(INDEX($C$2:$C$4,MATCH(A2,$B$2:$B$4,0)),A2)
The formula is need to be dragged down.
Single Formula & Array solution
Also this single ArrayFormula will do the trick:
=ArrayFormula(trim(transpose(query({IF(--REGEXMATCH(TRANSPOSE(A2:A7),$B$2:$B$4)=1,
REGEXREPLACE(TRANSPOSE(A2:A7),$B$2:$B$4,$C$2:$C$4),"");
TRANSPOSE(if(--not(REGEXMATCH(A2:A7,JOIN("|",B2:B4))),A2:A7,""))},,COUNTA(A2:A)))))
or this shorter formula:
=ArrayFormula(IFERROR(VLOOKUP(MATCH(A2:A7,B2:B4,0),{ROW(INDIRECT("a1:a"&COUNTA(C2:C4))),C2:C4},2,0),A2:A7))
Please, see explanations in Sample file

Lookup value based on latest matching criteria

Below is an example of a table I have, what I am trying to do is get the value in the value column for a specific criteria based on the last occurrence (not including today's date).
So in the example below I want to find the value for the last occurrence of 'A', which is 12.
I think this can be done using an Index-Match, I just can't get my head around it though.
For example
Todays Date: 15/12/2013
---------------------------------|
|Date | Criteria | Value
|--------------------------------|
|12/11/2013 | A | 3 |
|16/11/2013 | B | 6 |
|27/11/2013 | C | 7 |
|3/12/2013 | A | 12 |
|5/12/2013 | B | 8 |
|15/12/2013 | A | |
----------------------------------
EDIT:
I would also like to add that this formula will be in a different sheet to the table above. The sheet reference in the formula also needs to be dynamic, it will draw the sheet name from another cell.
I would use this formula:
=index(C:C,max(arrayformula(match(filter(A:A,B:B="A",C:C<>""),A:A,0))),1)
This formula assumes that your data is in the columns A,B,C and for every "A" value in the Criteria column, the Date is different. (If that's not the case, then this formula won't work, see below.
Let's look the formula inside from outside:
filter(A:A,B:B="A",C:C<>"") - This will result with the dates where there is an "A" in the Criteria column, and where the Value column is not empty.
arrayformula(match(filter(A:A,B:B="A",C:C<>""),A:A,0)) - In this step we basically find the row number in which those dates are present. The match function will search for the dates (counted in step 1). The arrayformula is needed because there will be more results.
max(arrayformula(match(filter(A:A,B:B="A",C:C<>""),A:A,0))) - This will find the maximum row number (The maximum row number which contains an "A" in the Criteria column)
index(C:C,max(arrayformula(match(filter(A:A,B:B="A",C:C<>""),A:A,0))),1) - Finally, we use the INDEX function to navigate to the value, which has the maximum row number.
Now, if you want this formula to work on another sheet, you should write, instead of for example:
=index(C:C,... => =index(Data!C:C,...
Assuming that your data is in your Data worksheet.
If you want to this sheet to be dynamic, it's a bit tricky. Let's assume, that you're getting the value of the sheet name from the G1 cell. Then you should write:
=index(indirect(concatenate(G1,"!C:C")),...
This is not so pretty as you should do this for every occasion when it occurs in that long formula (described earlier). Instead you can do some pre-work.
Let's write this to your H1 cell: =concatenate(G1,"!C:C") - If in the G1 cell the sheet name is "Data", then the H1 cell should contain: Data!C:C, similarly you can add to the
H2 cell: =concatenate(G1,"!A:A"),
H3 cell: =concatenate(G1,"!B:B")
Now you can write (and that's the final answer for your question I think):
=index(indirect(H1),max(arrayformula(match(filter(indirect(H2),indirect(H3)="A",indirect(H1)<>""),indirect(H2),0))),1) - where H1,H2,H3 will reference to your Data sheet's columns.
I hope it helps.
Use the following formula to accomplish that.
Formula
=QUERY(
B1:D6, // data
"SELECT D // select
WHERE // where clause
C = 'A' AND // first criterium
D IS NOT NULL // second criterium
ORDER BY B DESC // order by
LIMIT 1, // limit
0" // headers
)
for copy/paste
=QUERY(B1:D6, "SELECT D WHERE C = 'A' AND D IS NOT NULL ORDER BY B DESC LIMIT 1", 0)
Explained
The clue to the formula is the usage of the ORDER BY and the LIMIT options within the QUERY formula. The WHERE clauses will prepare the result in the first place. Next, column B (the dates) is ordered descendingly (highest first). The LIMIT option sets the amount of rows to be displayed at 1.
Example
I've created an example file for you: Lookup value based on latest matching Criteria
I appreciate this is a slightly old question, but there is a way that I achieved the goal of filtering an array which I found both more conceptually straightforward, and also more generally applicable than the other answers I have seen, using vlookup's definitional ability to pick the first matching value in an array.
PROBLEM, RESTATED:
Assuming sample data:
A...B...C...D...E, created by a google form
A is the form entry date
B, C and D are entries from a list (let's assume they are e.g. product name, geography, and sales date)
E is the value
If a new value is entered for a particular product, in a geography, on a date, then I want this to be used in preference to the older version of that same data.
SOLUTION:
If, in your form, you create three new columns:
F Unique test
G Test cells combined
H Unique cells
Then in column G, you create a combination of all the cells you want to test on (in this case B, C and E)
cell G2: "=arrayformula(B2:B & char(9) & C2:C & char(9) & D2:D)"
The next column is a restatement of the cells you want to filter based on (in this case the date in A)
cell H2: "=arrayformula(A2:A)"
And then finally in column F we actually undertake the test:
cell F2: "=arrayformula(A2:A=vlookup(G2:G,sort({G2:H},2,false),2,false))"
Breaking that down, the vlookup (vlookup(G2:G,[RANGE],2,false) compares the data in G2, G3...Gn with a [RANGE], which is a virtual array consisting of two columns, G and H, pre-sorted according to cell H in descending order.
i.e. For any unique value of G (the combination of test data) the vlookup will return the largest value of H
The last part is a simple comparison to the original data (A2, A3... An) to return TRUE or FALSE based on whether it is the latest version of the unique value.
A final step if needed would be to create a new sheet with "=filter('Form Responses 1'!A:E,'Form Responses 1'F:F=TRUE) to recreate the data without the older versions.
Hope this helps.

Resources