Google-Sheets Conditional Formatting based on multiple conditions - google-sheets

I am trying to format a cell based on multiple conditions. I am creating a spreadsheet to keep track of items borrowed. Let's say I am lending books. I want to have a list of books, one name in each cell. Then below that I want to have 3 columns: One column to enter the name of the book borrowed, the borrowing date, and the return date. I want to turn the cell with the book name RED, if the book has been borrowed AND if the return date is BLANK, meaning book is out. In my example screenshot, cell A2, and B2 should be red.
The conditional formula I have come up with is =AND($A6=A2, $C6="") for Book1 conditions, but it only works if C6 if empty, not if C8 is empty or other cells in column C where Book1 is found AND the return date is blank. There is no specific deadline to return items, just that if book has been borrowed and the return date in the same row is empty then the book name at the top should turn red.

Compare the result of COUNTA applied to the in and out ranges.
E.g. COUNTA(FILTER($B6:$B,$A6:$A=A2)) will count how many times a specific book is checked out, while COUNTA(FILTER($C6:$C, $A6:$A=A2)) will count how many times it is checked back in

Your question title asks about "multiple conditions", but very specifically you're looking to match based on any row that itself matches multiple conditions. That goes beyond the common AND operator and into a function that can process a range. You also need to be prepared for a book to be checked out and returned many times, which means there's no single row that manages the status of a given book; VLOOKUP and INDEX/MATCH are off the table too. Instead, you're effectively looking to generate a list of 0 or 1 values that match whether that book was checked out without being returned, and then coloring the cell based on whether there are any rows that match that condition.
To operate on multiple values at a time, you can use ARRAYFORMULA and then combine the output array with OR. However, one of the tricks about ARRAYFORMULA is that, to preserve the invariant about making single-value functions into array-valued functions, you can't use functions that can take arrays. This means that AND and ISBLANK don't work the way you'd like them to, but you can resolve that by using * instead of AND and = "" for ISBLANK.
One such solution (working example):
=OR(ARRAYFORMULA((A1 = $A$5:$A) * ($C$5:$C = "")))
ARRAYFORMULA isn't the only function to operate on a list of values, though; you could also use FILTER directly to only return matching rows. Here, you're checking whether any row has a matching book name and a blank return value, and then confirming that the value is not the #N/A that FILTER returns when nothing matches.
One such solution (working example):
=NOT(ISNA(FILTER($A$8:$C, $A$8:$A = A1, $C$8:$C = "")))
Of course, you can also take advantage of the fact that you're only checking blanks to use tehhowch's solution with COUNTA and FILTER above. However, since that solution won't work for arbitrary expressions, you can use ARRAYFORMULA or FILTER if your needs become more complex.

Related

Is there a way to specify an input is a single cell in Google Sheets?

I want to iterate over an array of cells, in this case B5:B32, and keep the values that are equal to some reference text in a new array.
However, SPLIT nowadays accepts arrays as inputs. That means that if I use the array notation of "B5:B32" within ARRAYFORMULA or FILTER, it treats it as a range, rather than the array over which we iterate one cell at a time.
Is there a way to ensure that a particular range is the range over which we iterate, rather than the range given at once as an input?
What I considered was using alternative formulations of a cell, using INDEX(ROW(B5), COLUMN(B5)) but ROW and COLUMN also accept array values, so I'm out of ideas on how to proceed.
Example code:
ARRAYFORMULA(
INDEX(
SPLIT(B5:B32, " ", 1), 1
) = "Some text here"
)
Example sheet:
https://docs.google.com/spreadsheets/d/1H8vQqD5DFxIS-d_nBxpuwoRH34WfKIYGP9xKKLvCFkA/edit?usp=sharing
Note: In the example sheet, I can get to my desired answer if I create separate columns containing the results of the SPLIT formula. This way, I first do the desired SPLITS, and then take the values I need from that output by specifying the correct range.
Is there a way to do this without first creating an output and then taking a cell range as an input to FILTER or other similar functions?
For example in cell C35 I've already gotten the desired SPLIT and FILTER done in one go, but I'd still need to find a way to sum up the values of the first character of the second column. Doing this requires that I take the LEFT value of the second column, but for that I need to output the results and continue in a new cell. Is there a way to avoid this?
Ralph, I'm not sure if your sample sheet really reflects what you are trying to end up with, since, for example, I assume you are likely to want the total of the hours per area.
In any case, this formula extracts all of the areas, and the hours worked, and is then easy to do further calculations with.
=ArrayFormula({REGEXEXTRACT({C5:C9;D5:D9;E5:E9;F5:F9;G5:G9;H5:H9},"(.*) \d"),
VALUE(REGEXEXTRACT({C5:C9;D5:D9;E5:E9;F5:F9;G5:G9;H5:H9}," (\d+)hrs"))})
Try that in cell E13, to see the output.
The first REGEXEXTRACT pulls out all the text in front of the first space and number, and the second pulls out all the digits in a string of " #hr" in each cell. These criteria could be modified, if necessary, depending on your actual requirements. Note that it requires the use of VALUE, to convert the hours from text to numeric values, since REGEXEXTRACT produces text (string) results.
It involved concatenating your multiple data columns into one long column of data, to make it simpler to process all the cells in the same way.
This next formula will give you a sum, for whatever matching room/task you type into B6, as an example.
=ArrayFormula(QUERY({REGEXEXTRACT({C5:C9;D5:D9;E5:E9;F5:F9;G5:G9;H5:H9},"(.*) \d"),
VALUE(REGEXEXTRACT({C5:C9;D5:D9;E5:E9;F5:F9;G5:G9;H5:H9}," (\d+)hrs"))},
"select Col1, sum(Col2) where Col1='"&B6&"' group by Col1 label sum(Col2) '' ",0))
I will also answer my own question given what I know from kirkg13's answer and other sources.
Short answer: no, there isn't. If you want to do really convoluted computations with particular cell values, there are a few options and tips:
Script your own functions. You can expand INDEX to accept array inputs and thereby you can select any set of values from an array without outputting it first. Example that doesn't use REGEXMATCH and QUERY to get the SUM of hours in the question's example data set: https://docs.google.com/spreadsheets/d/1NljC-pK_Y4iYwNCWgum8B4NJioyNJKYZ86BsUX6R27Y/edit?usp=sharing.
Use QUERY. This makes your formula more convoluted quite quickly, but is still a readable and universally applicable method of selecting data, for example particular columns. In the question's initial example, QUERY can retrieve only the second column just like an adapted INDEX function would.
Format your input data more effectively. The more easily you can get numbers from your input, the less you have to obfuscate your code with REGEXMATCHES and QUERY's to do computations. Doing a SUM over a RANGE is a lot more compact of a formula than doing a VALUE of a LEFT of a QUERY of an ARRAYFORMULA of a SPLIT of a FILTER. Of course, this will depend on where you get your inputs from and if you have any say in this.
Also, depending on how many queries you will run on a given data set, it may actually be desirable to split up the formula into separate parts and output partial results to keep the code from becoming an amalgamation of 12 different queries and formulas. If the results don't need to be viewed by people, you can always choose to hide specific columns and rows.

Sort Google Sheet by order values are entered in a data validation

Is there a way to sort a Google Sheet by the order in which values are entered into a data validation criteria?
I want to sort the sheet based in ascending order Low,Medium,High or descending order High,Medium,Low. Not by alphabetical order High,Low,Medium and Medium,Low,High respectively.
Aaron. The easiest way would be to use a helper column (which you can hide later if you like) wherein you assign numerical values to your Low, Medium and High (presumably 1, 2 and 3 respectively). Then you sort using the numerical column. It's fairly easy to write a one-cell array formula that would assign the numerical values to your labels. The numerical column need not be beside the label column; it can be any column.
Without seeing an actual sample sheet, I can't show you. But hopefully the concept is clear, and you can take it from there.
Added description after sheet was shared:
In the example sheet, Sheet1 Column A contained the Priority in words (Low, Medium, High) and Column B contained "other data." I placed the following array formula into C1:
=ArrayFormula({"Priority Val";IF(A2:A="","",VLOOKUP(A2:A,Data!A:B,2,FALSE))})
The formula is an array formula, hence the ArrayFormula() wrap.
Inside this are curly brackets {} which allow the building of arrays that are not "of a type." In this case, the header is listed first ("Priority Val"). The semicolon means "place the next part underneath." Then a VLOOKUP references every value in Column A (i.e., the priority words) against a simple chart in a second sheet named "Data." In that "Data" sheet, Column A simply lists 1, 2, 3 and Column B lists your exact words: Low, Medium, High. The IF() function just checks to see if a row in Sheet1!A:A is blank. If so, a null is assigned before trying the VLOOKUP; otherwise, every blank row would show an #NA error.
If you want to make it even more air tight, it's good practice to wrap VLOOKUP in IFERROR(), just in case you misspell something in Sheet1!A:A. That would look like this:
=ArrayFormula({"Priority Val";IF(A2:A="","",IFERROR(VLOOKUP(A2:A,Data!A:B,2,FALSE)))})
And you can avoid misspelling by applying data validation to Sheet1!A2:A, referencing Data!A:A as the only allowable answers. This is not strictly necessary; but I have done it in the sample sheet to show you.

Filter one sheet by a range in another sheet

I have a Google Spreadsheet document that I'm using to maintain a reference of all business logic on various systems. It is comprised of 2 sheets:
Sheet1 is a view of all of the logic. Each row has a unique code column (column B) and many details about the logic being done in other columns
Sheet2 is a mapping of the systems to the logic. Each system is on one row. From column E onward, each cell is exactly a code from Sheet1
The relationship between code and system is many to many, so the same code may be used by many systems, and each system may have many codes.
I would like to be able to filter Sheet1 based on whether the code column in each row is found for particular systems.
Example
System A and System B are in Sheet2 rows 50 and 51
Their codes are from column E to K
Filter Sheet1 by code where code is contained in Sheet2!E50:K51. The end result should be Sheet1 shows only those codes (and of course all columns for them)
I have seen and tried a bit of the usual suspects (ARRAY_FORMULA, INDEX, LOOKUP) but I do not yet grok them fully. I thought the answer would be going to "Filter -> By Condition -> Custom Formula is" but I'm not sure what to put there.
Any help is greatly appreciated!
Short Answer
In custom formulas of filters use INDIRECT to refer to ranges in another sheet.
To test if a value is in a 2D range, compare the value and the range, coerce booleans to numbers and sum them.
Explanation
Part 1: Custom Formulas in filters
Custom formulas in filters and conditional formatting rules can only reference the same sheet, using standard notation (='sheetname'!cell). To reference another sheet in the formula, use the INDIRECT function.
Example
Assuming that the filter criteria are in A2:A3, the filter custom formula in in a sheet called Sheet1 is:
=ISNUMBER(MATCH(A2,INDIRECT("Sheet2!$A$2:$A$3"),0))
Part 2: Test if a value is included in a 2D array
LOOKUP only could look for values in a single column or single row, by the other hand AND and OR functions can't be used in array formulas so, instead of use them we will compare a scalar value with the 2D range. This will return a 2D array of TRUE/FALSE values that we will coerce to number (1 for TRUE, 0 for FALSE) and sum them.
The final custom formula is the following one:
=ArrayFormula(SUM(N(A2=INDIRECT("Sheet2!E50:K51"))))
References
Filter your data
Apply conditional formatting rules

How do I populate a cell based on multiple criteria in Google Sheets?

So here is the situation. I have one spreadsheet in Google sheets that has a column for the names of TV stations. I have a second column that lists airing times for ads. This is the format the date and times are in.
14-12-22 08:06:05
I have a second sheet that has the same column for TV station names. I also have a column that has a time range in the format
09:00-16:00
Then there is a third column for Rate.
What I am trying to do is add a Rate column to the first spreadsheet and populate that my matching up the TV Station name and the time range on the second sheet. My first thought was a VLOOKUP but I'm trying to match 2 conditions with the second one being a bit tricky since I am using an exact time vs a time range.
Any ideas?
As it is permitted to parse the time intervals I would recommend doing so (say with something like =SPLIT(A1,"-") since the results might then be arranged into a compact matrix such as shown in the image in ColumnsF:J. The differences in the rates for different stations at different times are readily apparent.
I have left the above in the same sheet as one with a representation of your other data since I (am lazy and) don't know the relevant sheet names anyway - but prefix the relevant sheet name (and !) to the column references in the formula that are later in the alphabet than C:
=vlookup(A2,F:J,match(C2,$G$1:$J$1,1)+1,0)
With extraction of the time element (into ColumnC) of your data (from ColumnA) the formula attempts to find the time from C in the first row, but accepts an inexact comparison by defaulting to the next lower value where there is no exact match. Once found, the MATCH() function returns the position of the match relative to the start of the range searched.
This is then used in a VLOOKUP() function to determine how far across to return the result of a search for the exact A column value in ColumnF.
Details of the syntax of the functions may be found via Help > Function list.

Google Docs - SUMIF - SUM range if single cell contains a string

I'd like to quickly include or exclude an entire range of values in a SUM.
Presently I'm SUMing select cells for a grand total: [E19] =SUM(E13,E20,E30,E45,E55,E70,E80)
These are in turn SUMs of selected ranges:
... [E30] =SUM(E31:E44), [E55] =SUM(E56:E69), ...etc.
One of these ranges I would like to toggle it's inclusion in the Grand Total.
It seemed the best way to do it was this:
[E45] =SUMIF(D45,"☑",E46:E54)
In short, in cell E45 I'd like to SUM E46 to E54 only if D45 contains a ☑.
However Google Doc's SUMIF seems to only work with matched ranges: =SUMIF(D46:D54,"☑",E46:E54)
Is there a way to SUM a range only if a specific value exists in a single cell?
You're right about SUMIF, it allows you to sum values from a range, which meet a certain criteria (on another range of the same length). For example, if you had two columns called "status" and "price", you could use it to sum all the prices for a given status.
What you're trying to do can be done, instead, with the use of the IF function:
=IF(D45="☑";SUM(E46:E54);0)
If the condition specified in the first argument is true, it will return the second argument, that is, the sum. Otherwise, it will return the third argument, 0.
After working through the logic to share the issue I wound up identifying a solution. Rather than trying to force SUMIF to check a single cell against a range. I just nested the 1:1 SUMIF inside my 'Grand SUM': =SUM(E13,E20,E30,SUMIF(D45,"☑",E45),E55,E70,E80).

Resources