I'm trying to filter data based on email address matching and date matching.
My issue is the dates come in an unusual format (e.g: 2023-01-10 01:21:45 UTC).
I've been using a helper column instead to make the formula lighter. However, for automation purposes it would be much easier to have the true date format integrated to the formula.
Below is the formula I'm currently using in A2. My goal is to remove column D from formula and use only column C instead. I was trying to replace 'Sample Data for LOOKUP'!D:D by =ARRAYFORMULA(DATEVALUE(left(C2:C14,10))) but it does not work.
=filter('Sample Data for LOOKUP'!E:E,'Sample Data for LOOKUP'!D:D=MAXIFS('Sample Data for LOOKUP'!D:D,'Sample Data for LOOKUP'!B:B,"<>",ARRAYFORMULA(REGEXREPLACE('Sample Data for LOOKUP'!A:A,"(.+#)",)),REGEXREPLACE(B2,"(.+#)",)),(REGEXREPLACE(B2,"(.+#)",)=ARRAYFORMULA(REGEXREPLACE('Sample Data for LOOKUP'!A:A,"(.+#)",))),('Sample Data for LOOKUP'!B:B<>""))
Here is a sample file to make it easier to understand my issue:
https://docs.google.com/spreadsheets/d/18R-4m682SeHNBgnzJCM1l0Fef13D5vYG3gmeWDveSYQ/edit#gid=1722273432
I'm trying in cell A2 to cut column D in 'Sample Data for LOOKUP' tab. I would like to use column C instead with the unusual date format.
To get the latest Status for each email address domain listed in column B2:B, preferring statuses where column Lookup!B2:B is not blank, use vlookup() and sort(), like this:
=arrayformula(
iferror(
vlookup(
regexextract(B2:B, "#(.+)"),
sort(
{ regexextract(Lookup!A2:A, "#(.+)"), Lookup!E2:E },
sign(len(trim(Lookup!B2:B))), false,
Lookup!C2:C, false
),
2,
false
)
)
)
See your sample spreadsheet.
Related
Hey Stack Overflow Sheets, I have a question regarding a use case we want to create in our Google Sheet, either with built-in functionality, or with an extension like Sheetgo.
We have 2 sheets with multiple of the same columns (properties) and rows (users). The problem is that only one of the sheets is a trusted source for one column’s data (“source sheet”), and the other sheet has empty or outdated values for the same column (“outdated sheet”), and we need both sheets to have this column match values in rows that have a matching value for another column across both sheets (in our case, an “email” column). After they’re matching, we want to change the formula to sync any changes made for that column between both sheets.
Here’s an obfuscated data example:
Source sheet:
https://docs.google.com/spreadsheets/d/1uxqC3lB15UHhKTzjZyzzVIj5tlPjhCCCZ48xHYEcm0o/edit?usp=sharing
Outdated sheet:
https://docs.google.com/spreadsheets/d/1ckoCh8gMwt2QeBRH1dB2dyFPJUukrjQ-SCgucTL8rhc/edit?usp=sharing
In the example, we’re looking for a formula that would allow us to have a “Type” column value injected into the Outdated Sheet’s Type column, based on both sheet’s matching Email column value. And then, have it so if a row’s “Type” value changes in either doc, the other doc follows.
What formula or extension would I use to go about this? Any help appreciated, thanks!
I tried to create a VLOOKUP and MATCH formula, but I couldn't yet figure out how to have the function first LOOKUP into the Source Sheet, then inject it into the Outdated Sheet based on a matched email column value. Sheetgo made the LOOKUP easier, but I still couldn't figure out how to do an exact operation.
Use importrange() and vlookup(). Put this formula in cell A1 of the target spreadsheet:
=arrayformula(
lambda(
import,
iferror(
vlookup(
C1:C,
{ index(import, 0, 3), index(import, 0, 1) },
2, false
)
)
)(
importrange("1uxqC3lB15UHhKTzjZyzzVIj5tlPjhCCCZ48xHYEcm0o", "Sheet1!A1:F")
)
)
I am trying to make an automated attendance sheet
I have 2 google sheets,
the first one is the responses from a google form that has the name of the students and the date they attended, so it will have duplicated name and duplicated dates.
The second sheet have the names of the students on the left and the dates on the top.
I am trying to automate the second sheet to put "P" under the date that the student was present and "A" when his name is not in the first sheet with that date.
Best i could do was adding an extra column with the letter "p" in the first sheet and using dget to search for the name and date and output the "p" from the extra column, which only worked for one of them for some reason.
=DGET('ATTENDANCE DATE !B:D, "AT", {"NAME", "DATE"; $H$4,12})
I tried to use query also but no luck.
=QUERY('ATTENDANCE DATE'!B7:D,"
SELECT D
WHERE B MATCHES'"&$H9&"' AND C MATCHES '"&I$2&"'
")
Sorry if my question was confusing.
A good solution is to use 4 formulas to do exactly what you like. Each formula has a function:
B1 formula: generates the headers for all the dates with data.
B2 formula: generates the sub-header with the day of the week for each date.
A3 formula: gets all the names.
B3 formula: gets the attendance values for all users. This is the most complexs one.
Here is how it looks:
A
B
1
< fromula 1 >
2
name
< formula 2 >
3
< formula 3 >
< formula 4 >
Before starting there a few things to note
Questions and more information
Please, if at any point you don't understand something, let me know (I'd like this to be a nice resource on how to do formulas).
Also, at the end I left links to all the formulas I use, so you can see what they exactly do.
Locale
I'm using the English locale. this means that I'm using commas , to separate arguments (instead of ;) and array literals (instead of \). if you have function formatting errors, look into it, as this could be the issue.
Sheet names
I've changed the Sheet's names as they are very long and made the formulas harder to follow. Fell free to replace the names on the formulas back to the original name. Here is how I named them:
ATTENDANCE RESPONSES FROM GOOGLE FORM ⟶ Att
LATE/ABSENT RESPONSES FROM GOOGLE FORM ⟶ Late
Formula format
Almost all formulas require "ARRAYFORMULA" to show their full effects. I won't be adding it everywhere as it could get confusing. If you'd like to see what a formula part (doesn't have an equal sign =) does, go to a sheet and do:
=arrayformula(
<paste formula part>
)
Also, parts that are in <some name> are not literal, and represent the code named in between the brackets.
Formula 1
It can be split into 2 formulas:
Get the ordered unique dates
Add a Reason column for each date
Get the dates
The first thing you can use is UNIQUE to get only the unique ones and SORT to sort them. You also need to get them from both sheets as there could be a day that everyone is absent or another where everyone came. SORT(UNIQUE({Att!B2:B; Late!B2:B})) does most of the trick but you also get empty cells. because of that we add a filter. So together:
SORT(UNIQUE(FILTER({Att!B2:B; Late!B2:B}, {Att!B2:B; Late!B2:B}<>"")))
Adding Reason
The problem of it is that the number of column is not fixed (it grows over time). A good workaround is to concatenate the date with a separator and Reason and then split it again. This only works for columns and generates a 2 column, result. Then it can be moved into a single column by using FLATTEN.
FLATTEN(SPLIT(
<previous part>&"␟Reason",
"␟"
))
I'm using ␟ (Symbol For Unit Separator) as the separator as it indicates exactly what it is and is very-very unlikely to be included in the sheet.
If you use that you'll see that the date is shown in numbers. To Change that we'll format the date before concatenating and splitting:
FLATTEN(SPLIT(
TEXT(
<previous part>,
"dd/mmm/yyyy"
)&"␟Reason",
"␟"
))
Now we need to make it a row instead of a column. There is a function that does that: TRANSPOSE.
Complete formula 1
=ARRAYFORMULA(
TRANSPOSE(FLATTEN(SPLIT(
TEXT(
SORT(UNIQUE(FILTER({Att!B2:B; Late!B2:B}, {Att!B2:B; Late!B2:B}<>""))),
"dd/mmm/yyyy"
)&"␟Reason",
"␟"
)))
)
Formula 2
To add the day of the week we need to format the date with TEST and the format ddd, which is the short-version of the name of the day of the week (Mon, Tue, etc).
TEXT(B1:1, "ddd")
Note though that if the value formatted is already text, it will pass it. Because of that, we need to only do this for the columns with dates. One way that I found is to get the even-numbered columns. TO do that, it's a combination of COLUMN (get the number of the column), MOD (get the module), and IF:
IF(MOD(COLUMN(B1:1),2)=0, <formatted text>, "")
This does what we want but we now get "Sun" on columns that there is nothing. The reason is that empty cells are being interpreted as zeros. Because of that we need to add another condition: the cell is not empty.
IF((MOD(COLUMN(B1:1),2)=0)*(B1:1<>""), <formatted text>, "")
To do the logical and I'm using the product because the formula AND would return a single value ("eats" the passed array).
Complete
=ARRAYFORMULA(
IF(
(MOD(COLUMN(B1:1),2)=0)*(B1:1<>""),
TEXT(B1:1, "dddd"),
""
)
)
Formula 3
The third formula is the simplest and should be self-explanatory:
=ARRAYFORMULA(
SORT(UNIQUE(Att!A2:A))
)
Formula 4
This is the final formula. This formula is based on using VLOOKUP to know the value for each person and date.
Making a table to VLOOKUP into
The way of doing that is to generate a key by joining both values into a single text value and set the other values on the other columns. To prevent problems we add a separator to make sure that there are no combination that will be equal. Here is how the table to lookup into looks like:
< name >␟< date >
< status >
< reason >
< name >␟< date >
< status >
< reason >
< name >␟< date >
< status >
< reason >
⋮
⋮
⋮
The key for the first sheet is:
Att!$A$2:$A&"␟"&Att!$B$2:$B
To add the other 2 columns (Present and an empty one) we use a similar trick to Formula 1: we add a separator to split it later on. Because we already are using ␟ for the key, we need another one. In the same block there is another meant for this cases: ␞ (Symbol For Record Separator).
Att!$A$2:$A&"␟"&Att!$B$2:$B&"␞"&"Present"&"␞"&""
or joining the literal text:
Att!$A$2:$A&"␟"&Att!$B$2:$B&"␞Present␞"
This need to be filtered, as there are empty values, which we don't want. We'll use FILTER to do exactly that:
FILTER(Att!$A$2:$A&"␟"&Att!$B$2:$B&"␞Present␞", Att!$A$2:$A<>"", Att!$B$2:$B<>"")
For the second sheet, we do something similar but including the other columns:
FILTER(Late!$A$2:$A&"␟"&Late!$B$2:$B&"␞"&Late!$C$2:$C&"␞"&Late!$D$2:$D, Late!$A$2:$A<>"", Late!$B$2:$B<>"", Late!$C$2:$C<>"")
Note that I've added more conditionals.
This needs to be vertically joined. This can be done with an array literal:
{
<Attr formula>;
<Late formula>
}
Then we need to split the rows to expand into the multiple columns:
SPLIT(
{
FILTER(Att!$A$2:$A&"␟"&Att!$B$2:$B&"␞Present␞", Att!$A$2:$A<>"", Att!$B$2:$B<>"");
FILTER(Late!$A$2:$A&"␟"&Late!$B$2:$B&"␞"&Late!$C$2:$C&"␞"&Late!$D$2:$D, Late!$A$2:$A<>"", Late!$B$2:$B<>"", Late!$C$2:$C<>"")
},
"␞"
)
Using VLOOKUP
Now that we have where to lookup into, we can do it like so:
VLOOKUP(
A3:A&"␟"&C1:1,
<lookup table>,
2,
false
)
Note that the key that we are looking up is the one we generate. Also, this will get the values only below the dates (will fail otherwise).
Adding the reason
Since we know that the cells which are for the reason fail (since <name>␟Reason shouldn't exist), we can use IFERROR to detect it:
IFERROR(
<vlookup status>,
<vlookup reason>
)
The formula for reason is almost identical to the one for status. The only changes are that we lookup into the third column (instead of the second) and we look one to the left:
VLOOKUP(
A3:A&"␟"&OFFSET(C1:1, 0, -1),
<lookup table>,
3,
false
),
Using OFFSET instead of a range ensures that they have the same size.
Final error management
This formula fails when the key doesn't have name or date (which is outside the table or there that entry missing). For that case we add another IFERROR:
IFERROR(
<formula>,
""
)
Complete formula
=ARRAYFORMULA(
IFERROR(
IFERROR(
VLOOKUP(
A3:A&"␟"&C1:1,
SPLIT(
{
FILTER(Att!$A$2:$A&"␟"&Att!$B$2:$B&"␞Present␞", Att!$A$2:$A<>"", Att!$B$2:$B<>"");
FILTER(Late!$A$2:$A&"␟"&Late!$B$2:$B&"␞"&Late!$C$2:$C&"␞"&Late!$D$2:$D, Late!$A$2:$A<>"", Late!$B$2:$B<>"", Late!$C$2:$C<>"")
},
"␞"
),
2,
false
),
VLOOKUP(
A3:A&"␟"&OFFSET(C1:1, 0, -1),
SPLIT(
{
FILTER(Att!$A$2:$A&"␟"&Att!$B$2:$B&"␞Present␞", Att!$A$2:$A<>"", Att!$B$2:$B<>"");
FILTER(Late!$A$2:$A&"␟"&Late!$B$2:$B&"␞"&Late!$C$2:$C&"␞"&Late!$D$2:$D, Late!$A$2:$A<>"", Late!$B$2:$B<>"", Late!$C$2:$C<>"")
},
"␞"
),
3,
false
)
),
""
)
)
Final touches
The final result is something like this.
After that you can simply add formats to your taste. You can also add conditionals ones to more easily see the result.
References
MOD (Google Editors Help)
SPLIT (Google Editors Help)
TEXT (Google Editors Help)
IF (Google Editors Help)
IFERROR (Google Editors Help)
FILTER (Google Editors Help)
UNIQUE (Google Editors Help)
SORT (Google Editors Help)
TRANSPOSE (Google Editors Help)
FLATTEN (Google Editors Help)
ARRAYFORMULA (Google Editors Help)
VLOOKUP (Google Editors Help)
OFFSET (Google Editors Help)
I've completed a not-so-neat solution for you, starting on Row10 in the 'AUTO ATTENDANCE' sheet. It's divided into 4 parts:
The formula in cell D10 auto-populates Row10 with dates and empty cells in between:
=SPLIT(JOIN("|REASON|",SORT(UNIQUE({'ATTENDANCE RESPONSES FROM GOOGLE FORM'!$B$2:$B;'LATE/ABSENT RESPONSES FROM GOOGLE FORM'!$B$2:$B}))),"|")
Row 11 gets the day of the week from row 10 (if the cell above it contains a date:
=IF(ISDATE(D10),TEXT(D10,"dddd"),)
Cell C12 gets all unique names from both response sheets (auto-populates the name column):
=SORT(UNIQUE({'ATTENDANCE RESPONSES FROM GOOGLE FORM'!$A$2:$A;'LATE/ABSENT RESPONSES FROM GOOGLE FORM'!$A$11:$A}))
Cell D12 onwards gets the form responses and does the auto-attendance:
=IF($C12<>"", IF(ISDATE(D$1), IF(IFERROR(QUERY('ATTENDANCE RESPONSES FROM GOOGLE FORM'!$A$2:$B,"select A where A = '"&$C12&"' AND B = datetime '"&TEXT(D$1, "yyyy-mm-dd hh:mm:ss")&"'"), "noresult")=$C12, "PRESENT", IFERROR(QUERY('LATE/ABSENT RESPONSES FROM GOOGLE FORM'!$A$2:$D, "select C where A = '"&$C12&"' and B = datetime '"&TEXT(D$1, "yyyy-mm-d hh:mm:ss")&"'"), "NO RESPONSE")), IFERROR(QUERY('LATE/ABSENT RESPONSES FROM GOOGLE FORM'!$A$2:$D, "select D where A = '"&$C12&"' and B = datetime '"&TEXT(C$1, "yyyy-mm-d hh:mm:ss")&"'"), )), )
The cells with yellow background contain formulae, the ones with green background do not contain formulae but will be auto-populated as the forms get more responses. The single cell with red background (C11), you'll have to write manually ;) Hope this solves your issue!
I have a simple sheet to try to track and format race results from a league that I've joined. For the most part I know how I want to do this but when I use a query it's dropping data in some situations and formatting it strangely in others.
It seems as if where there are more numbers in a column than text it drops all text entries.
In addition for some reason when I add a check row, if it's included in the query it pushes almost all the data into a single cell except for the check row.
Would someone mind having a look and trying to figure out why it's doing this. Link Below
On sheet RRL1 I have my compiled data on the left, my 'missing' data on the right and my weirdly formatted data below.
https://docs.google.com/spreadsheets/d/1c9xlQG06dQCrpMk3UMAX29oTlpRuhTfx6btbYTGmC8g/edit?usp=sharing
The query() formula will only support one data type per column — number, text, boolean or date. The type is determined by the majority of the values in the first few hundred rows. Values that are of another type will be returned as null, i.e., blank values.
=QUERY('Tournament Details'!D2:E22)
Use an { array expression } like this:
={ 'Tournament Details'!D2:E22 }
=TRANSPOSE(query('Tournament Details'!I3:I26))
Use this:
=transpose('Tournament Details'!I3:I26)
Use this pattern to replace "DNS" and "DNF" with nulls:
=arrayformula(
query(
{ 'RRL1'!A1:C, iferror(value('RRL1'!D1:D)) },
"select Col3, sum(Col4)
where Col3 is not null
group by Col3
label sum(Col4) 'Total AUS RRL1' ",
1
)
)
The "squished" values you mention come about because you are not specifying the headers parameter. The best practice is to always include it, like this:
=query('Tournament Details'!A2:E22,"select A where C != 'N/A'", 1)
Using Zapier, when someone fills out my Wufoo application form, a line is created with some of the information, including Date Created as well as the locations selected from a checkbox field. On my second sheet, I want to be able to have a total of how many applications have come in just today for each location. I figured the easiest way to do this would be a CountIFs function, but I'm probably wrong.
https://docs.google.com/spreadsheets/d/1mIw_O6KT2QCyKeKmZ4aJ1EHzOkZ4xj49ZyjEMOCwUxA/edit#gid=0
Here is a copy of what I'm building if you'd like to experiment. I'm using =countifs(Sheet1!E2:T1000,"Buford,GA (Atlanta)",Sheet1!E2:T1000,"="&TODAY()) to try to find this, but always get 0 as the result.
try this:
You needed to specify the columns, in your case: E2:E to look up for the name, and S2:S for the date.
=countifs(Sheet1!E2:E,"Buford, GA (Atlanta)",Sheet1!S2:S,"="&TODAY())
You can also use Partial Match in order to use your headers in Sheet2 as the first criteria in your countifs:
=countifs(Sheet1!E2:E,"*"&B$1&"*",Sheet1!S2:S,"="&TODAY())
Then you had a problem of formatting in Sheet1 within the Date's Column (S): your second date in cell S3 was formatted as Date Time, as oppose to your first date in S2 which was formatted as Date only.
Note: The above suggestions are to resolve your personal attempt, otherwise they are other ways of achieving what you're looking for.
UDPATE (ALTERNATIVE SOLUTION):
you could use the following QUERY which summarize everything within a table and sort it in descending order:
= {"Names","Count";
ARRAYFORMULA(
SORT(
TRANSPOSE(
SUBSTITUTE(
QUERY(Applications!D1:T,
"Select Count(D),Count(E), Count(F), Count(G), Count(H), Count(I), Count(J),
Count(K), Count(L), Count(M), Count(N), Count(O), Count(P), Count(Q), Count(R), Count(S) where T = date '"&TEXT(today(),"yyyy-mm-dd")&"'
"),
"count", "")
),
2, 0)
)
}
I'm creating a database on Google Sheets for work and while I'm aware it's not the best solution, due to a number of restraints, that's what I've got to work with atm.
The thing is, I'm creating this for people who don't really know how to work with formulas on Google Sheets so I'm trying to be as user friendly as I can.
I'll use this sample sheet to try and demonstrate what I'm trying to do:
https://docs.google.com/spreadsheets/d/1tXM0IlswQVdwFum9a0pR5NsbtL5Uq_AH1tPbytXGvVg/edit#gid=0
One of the sheets is the Database, which will countain multiple columns of data (there's 10 on the sample, but the actual database is much larger).
There is another sheet called Column Index where I have a list of all columns, what kind of data they represent and a checkbox for people to select what data they want.
Finally, theres a third sheet called Data Extraction and I want to get the checked columns from the Database and send them to this sheet so people can download or copy this data to other worksheet.
It looks like a QUERY situation to me, but I'm not sure if it's possible to do it dynamically
This should do it:
=ArrayFormula(QUERY(
Database!A:K,
"select A,"&
TEXTJOIN(
",",
1,
IFNA(
REGEXEXTRACT(
ADDRESS(
1,
MATCH(
IF(
'Column Index'!C2:C,
'Column Index'!B2:B,
""
),
Database!1:1,
0
)
),
"[A-Z]+"
)
)
)
))
I built the query string, selecting the column indices that we wanted. No need for the "Col Index" Column.
Using Address, we can generate the appropriate column letter using a column address, then we just extract the letters part with a regex.
What I got was not that different as I also tried to construct the query string. The downside is it may be a bit buggy (but it works)
Here it is:
=query(Database!A1:K15,"select A,"&join(",",ArrayFormula(SUBSTITUTE(ADDRESS(1,filter(row('Column Index'!C2:C11),'Column Index'!C2:C11),4), "1", ""))))