I have tables with Start and End time data entered in either an AM/PM cell for each day in this spreadsheet. How do I organize and display the number of hours between the two times to end up with a graph that looks like the second image below?
Starting data
Desired data
Challenges/variables:
Data is provided in free text so it may not be in a time format. Usually it is 1, 2, 4 or 5 characters but it might be anywhere from 1 -5 characters with some variations depending on the use of a colon. For example, 1, 10, 130, 1:30, 1130, 12:30.
My approach
IF(RIGHT(B2,2)="AM",text(IF(AND(LEN(C2)>0,LEN(C2)<3),
C2&":00",IF(LEN(C2)>3, C2, "")), "HH:MM AM/PM"),
IF(RIGHT(B2,2)="PM",text(IF(AND(LEN(C2)>0,LEN(C2)<3), 12+C2&":00",IF(LEN(C2)>3,
12+split(C2,":")&":"&RIGHT(C2,2), "")), "HH:MM AM/PM"),""))
I used length to figure out if something was already in a time format, and convert those that weren't. I added 12 to any PM value. If it was blank, it would result in a blank space.
Limitations:
I couldnt get it to work as an array (not sure why)
I realized afterwards that this would not work for 3 or 4 characters where there was no colon Entries like 1120, 145 wont work, for example 7:00 - 1120 = 7:00.
Possible solutions?
1.I think probably a REGEX would work better to convert anything into a time format but other solutions would be possible such as seeing if the 3rd character from the Right was equal to :
2. As far as the reorganization, I think it will require some combination of filter, transpose, or query, but I think a prerequisite might be getting the conversion to work as an array of some sort.
Thanks in advance for your help. The shared spreadsheet is here.
You'll have to add in some more if new time formats are added, but give this a swing
=ARRAYFORMULA(
TRANSPOSE(
QUERY(
QUERY(
IF(ISBLANK(C2:C),,
{A2:A,REGEXEXTRACT(B2:B,"(.*) \|"),
IF(REGEXMATCH(TO_TEXT(C2:C),"AM|PM"),C2:C,
IF(REGEXMATCH(TO_TEXT(C2:C),":"),--(TEXT(C2:C,"HH:MM")&" "&RIGHT(B2:B,2)),
IF(LEN(C2:C)<3,--(C2:C&":00 "&RIGHT(B2:B,2)),
--(REGEXREPLACE(TO_TEXT(C2:C),TO_TEXT(RIGHT(C2:C,2)),"")&":"&RIGHT(C2:C,2)&" "&RIGHT(B2:B,2)))))}),
"select Col1, Max(Col3)
where
Col3 is not null and
Col1 is not null
group by Col1
pivot Col2
label Col1 'Day'
format Max(Col3) 'hh:mm am/pm'"),
"select Col1, Col3, Col2")))
I also added your duration difference to your sheet.
=ARRAYFORMULA(
IF(ISBLANK(H9:J9),,
IF(H11:J11<=H10:J10,
1+H11:J11-H10:J10,
H11:J11-H10:J10)))
The ranges will be different, depending on where you have it. It would be best to remove the TRANSPOSE from the first formula so the days run down the column. I included a demo of this in your sheet.
see:
=ARRAYFORMULA(IF(ISNUMBER(C2:C15)*(IFERROR(TIMEVALUE(C2:C15), 2)<=1), TIMEVALUE(C2:C15),
IF(ISNUMBER(C2:C15)*(IFERROR(TIMEVALUE(C2:C15), 2)=2),
IFERROR(TIMEVALUE(C2:C15&":00 "®EXEXTRACT(B2:B15, "AM|PM")),
TIMEVALUE(REGEXREPLACE(C2:C15&"", "(\d+)(\d{2})$", "$1:$2 ")®EXEXTRACT(B2:B15, "AM|PM"))),)))
Related
I have sales data that gives me dates in a bad format. Every new sale gets automatically added to the sheet. Looks like this:
Column A
Column B
Column C
Order 1
2022-12-02T02:09:37Z
$1025.19
Order 2
2022-12-02T01:25:15Z
$873.65
This will continue on for all sales. Now the date format is UTC for whatever reason and I can't adjust that, so within this formula I have to subtract 6 hours to get it to central time. I'm trying to create an auto-updating chart that shows an average day for 7 days, so I'm trying to do a sumif formula.
Here's what I have on Sheet2:
=sumif(Sheet1!C:C,index(split((index(split(Sheet1!B:B,"T"),1)+index(split(left(Sheet1!B:B,19),"T"),2))-0.25,"."),1),A1)
Where A1 is a single date. Testing this with one date and not the range shows that it does match. When I do the range, the total comes to 0, even though multiple different dates should match. What am I doing wrong?
Assume A1 has the value: 2022-12-02T02:09:37Z
Apply this formula:
=LAMBDA(RAW,TUNEHOUR,
LAMBDA(DATE,TIME,
TEXT((DATE&" "&TIME)+TUNEHOUR/24,"yyyy-mm-dd hh:mm:ss")
)(TEXT(INDEX(RAW,,1),"yyyy-mm-dd"),REGEXREPLACE(INDEX(RAW,,2),"Z",""))
)(SPLIT(A1,"T"),-6)
returns:
2022-12-01 20:09:37
And assume you have a set of data like this:
you can apply this formula:
=ArrayFormula(
LAMBDA(DATES,AMOUNTS,START,END,DFORMAT,TFORMAT,SKIPBLANK,TUNEHOUR,
LAMBDA(DATES,AMOUNTS,DTFORMAT,START,END,
LAMBDA(DATES,TIMES,
LAMBDA(VALIDDATES,AMOUNTS,
TEXT(SUM(FILTER(AMOUNTS,VALIDDATES>=START,VALIDDATES<=END)),"$#,##0.00")
)(TEXT((DATES&" "&TIMES)+TUNEHOUR/24,DTFORMAT),IF(ISNUMBER(AMOUNTS),AMOUNTS,VALUE(REGEXEXTRACT(AMOUNTS,"^\$(.+)"))))
)(TEXT(INDEX(DATES,,1),DFORMAT),REGEXREPLACE(INDEX(DATES,,2),"Z",""))
)(SPLIT(QUERY({DATES},SKIPBLANK),"T"),QUERY({AMOUNTS},SKIPBLANK),DFORMAT&" "&TFORMAT,TEXT(START,DFORMAT)&" 00:00:00",TEXT(END,DFORMAT)&" 23:59:59")
)($B$5:$B,$C$5:$C,$B$1,$B$2,"yyyy-mm-dd","hh:mm:ss","WHERE Col1 IS NOT NULL",-6)
)
Where you enter a start date and an end date at B1 & B2 to sum up the amount with.
The provided date column will be deducted by 6 hours.
What this formula does is...
format the date column into a valid date,
compare dates from step 1 with a given start and end date as filter condition,
filter the given amount column with conditions from step 2,
sum the result of filter from step 3 as an array,
format the output as price.
Use regexreplace() and query(), like this:
=arrayformula(
query(
{
weeknum(
regexreplace(B2:B, "([-\d]+)T(\d\d:\d\d).+", "$1 $2")
-
"6:00"
),
C2:C
},
"select Col1, avg(Col2)
where Col1 is not null
group by Col1
label Col1 'week #' ",
0
)
)
I think you're trying to split the values and sum them. I can't understand fully what's the purpose of 19 in LEFT function, and why are you again splitting it? Maybe some approach similar to yours is use LEFT function with 10 characters for the date, and MID from 12th character to get the time. Then substract .25 for the 6 hours as you did, and ROUNDDOWN with 0 digits to get the only the day
=ARRAYFORMULA(ROUNDDOWN(LEFT('Sheet1'!B:B,10)+MID('Sheet1'!B:B,12,8)-0.25,0))
And then you can insert it in your SUMIF:
=SUMIF(Sheet1!C:C,ARRAYFORMULA(ROUNDDOWN(LEFT(Sheet1!B:B,10)+MID(Sheet1!B:B,12,8)-0.25,0)),A1)
community!
I have a table of 3 columns in Google Sheets: Date, Name, Amount.
I want to process data from it, so for every date in the list, there will be a full list of participants and amounts.
If there is no amount for specific date and person, it will be "0", or just leave it blank.
In addition, would like to count the percent of the sum of the amount for each person till the date in the corresponding row.
And it should be dynamically updated, so if a new row added with new name or date or both, so new participant will be added to every date in the output table and new full list of participants for the new date created.
For better understanding, here is the example of the data and output tables
What I've tried?
In MS access query it could be done not so hard.
Here I tried to create 2 new lists of unique dates and participants and connect them through use of CONCATENATE, ARRAYFORMULA, then SPLIT and some QUERY. All this through use of helping column of text, which should be edited manually for every new row...
The code in helping column:
=concatenate(arrayformula(if(isblank($F$3:$F),,";"&$E3&","&$F$3:$F)))
Then split code:
=query(arrayformula(split(transpose(split(TEXTJOIN(";",true,$G$3:$G),";",true,true)),",",true,true)),"Select Col1,Col2 where Col2 is not null order by Col1 ASC",0)
But here I stuck...
Want to pull the amounts for every corresponding date and participant, but...
FILTER reaches first, not existent in the original table combination, and doesn't proceed.
QUERY doesn't fetch the data fully automatically for all the list in the output table.
VLOOKUP gives only one row or complete mess, when use it recursively, or error...
So, how can I do this (if it's possible at all) in google sheets, and so all the output will be fully automatically updated?
Thank you very much!
Update - based on comments
I could not figure out a way to make this through one formula. If this works, you can have a hidden column (say H here) that totals the amount for the person till that date using the formula =QUERY(FILTER($E$3:$G, $F$3:$F = F3, $E$3:$E <= E3), "select sum(Col3) label sum(Col3) ''", 0) in H3.
Then in I3 you can find the % of total till date using the formula =QUERY(FILTER($E$3:$G, $F$3:$F = F3, $E$3:$E <= E3), "select sum(Col3) label sum(Col3) ''", 0)/SUMIF($E$3:$E, E3, $H$3:$H).
Both of the formulae in H3 and I3 need to be dragged down unlike the one in E3. Perhaps someone will be able to offer a better solution.
Previous answer
You can try something like this:
In E3 you can have the formula =ArrayFormula({(FLATTEN(SPLIT(REPT(FILTER(UNIQUE(A3:A)&"✦", UNIQUE(A3:A)>0), COUNTA(UNIQUE(B3:B))), "✦"))), (TRANSPOSE(SPLIT(REPT(JOIN("", FILTER(UNIQUE(B3:B)&"◼︎", UNIQUE(B3:B)<>"")), (COUNTA(UNIQUE(A3:A)))), "◼︎"))), (IFNA(VLOOKUP({(FLATTEN(SPLIT(REPT(FILTER(UNIQUE(A3:A)&"✦", UNIQUE(A3:A)>0), COUNTA(UNIQUE(B3:B))), "✦")))&(TRANSPOSE(SPLIT(REPT(JOIN("", FILTER(UNIQUE(B3:B)&"◼︎", UNIQUE(B3:B)<>"")), (COUNTA(UNIQUE(A3:A)))), "◼︎")))}, {A3:A&B3:B, C3:C}, 2, 0), 0))}). It is a little long but fills Columns E through G dynamically.
Then in H3 you can have the formula =ArrayFormula(IFERROR(((IFNA(VLOOKUP({(FLATTEN(SPLIT(REPT(FILTER(UNIQUE(A3:A)&"✦", UNIQUE(A3:A)>0), COUNTA(UNIQUE(B3:B))), "✦")))&(TRANSPOSE(SPLIT(REPT(JOIN("", FILTER(UNIQUE(B3:B)&"◼︎", UNIQUE(B3:B)<>"")), 3), "◼︎")))}, {A3:A&B3:B, C3:C}, 2, 0), 0))/(SUMIF((FLATTEN(SPLIT(REPT(FILTER(UNIQUE(A3:A)&"✦", UNIQUE(A3:A)>0), COUNTA(UNIQUE(B3:B))), "✦"))), (FLATTEN(SPLIT(REPT(FILTER(UNIQUE(A3:A)&"✦", UNIQUE(A3:A)>0), COUNTA(UNIQUE(B3:B))), "✦"))), G3:G))), "")). This one is dynamic as well.
I tried with your data and added a row on my own and it works.
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)
We have hit the dreaded 5 million rows limit which is so small for any semi-serious data.
We have an important ArrayFormula piece in one of our worksheets (tab) currently that summarizes the data from another worksheet in the same file where time series data is kept with dates. This is our current function:
=ArrayFormula(SUMIFS(DataSheet!$B:$B,
MONTH(DataSheet!$A:$A), 1,
YEAR(DataSheet!$A:$A), 2020)
)
Explanation: This basically summed all of column B in the DataSheet tab for the month of Jan 2020 based on date found in column A of that sheet.
However, this worksheet of data that is now running close to that row limit. We can move it to another Google Sheets file, and refer to the same data via IMPORTRANGE.
The question then is how to refer to that data instead of the DataSheet!$A:$A in the above old formula? Will this reference be replaced by the entire IMPORTRANGE function?
Old:
=ArrayFormula(SUMIFS(DataSheet!$B:$B,
MONTH(DataSheet!$A:$A), 1,
YEAR(DataSheet!$A:$A), 2020)
)
New:
=ArrayFormula(SUMIFS(IMPORTRANGE(filename, rows)!$B:$B,
MONTH(IMPORTRANGE(filename, rows)!$A:$A, 1,
YEAR(IMPORTRANGE(filename, rows)!$A:$A, 2020)
)
This does not work of course, because we cannot have the exclamation ! followed by the column in an importrange. Any other thoughts?
Try this in cell A1 on a fresh, brand new tab somewhere:
=ARRAYFORMULA(QUERY(1*TEXT(IMPORTRANGE("[spreadsheet key]","Sheet1!A:B"),{"mmmyyyy","0.00"}),"select Col1,SUM(Col2) where Col2<>0 group by Col1 order by Col1")
The "spreadsheet key" is the combination of letters and numbers after the "/d/" and before the "/edit..." in the URL of your source sheet.
Obviously, you'd also replace "Sheet1!A:B" with whatever the real tab/column reference is.
Then, select all of Column A and from the Menu choose Format>Number>More Formats>Custom Number Formatting, Then this in the dialog box:
mmmm yyyy
You want to IMPORTRANGE from two different sheets in a different spreadsheet.
While the following formula will import data from both sheets, it will also import the blank rows, so you might have to scroll down hundreds of rows in order to see the data from the second sheet (and this might give your the wrong impression that the second sheet is not getting imported):
{
IMPORTRANGE("SPREADSHEET_ID","CurrentMonth!$A:$J");
IMPORTRANGE("SPREADSHEET_ID","All2020!$A:$J")
}
You can use QUERY in order to filter out blank rows:
=QUERY(
{
IMPORTRANGE("SPREADSHEET_ID","CurrentMonth!$A:$J");
IMPORTRANGE("SPREADSHEET_ID","All2020!$A:$J")
},
"SELECT * WHERE Col1 IS NOT NULL ORDER BY Col1 DESC"
)
Note:
I thought you'd like to sort the data according to the date in column A, please remove ORDER BY Col1 DESC if that's not the case.
I have a table like that.
I can't get my head around how to traverse(query selectively) through the countries and output data per date. Sometimes I need one country, sometimes 3 or 5.
I just need to have a separate table where I'll have something like that for later processing (charts and other calculations).
Usually, I'd use something like
=QUERY(A1:100, "SELECT a column WHERE a row ='Name of a country'")
or
=TRANSPOSE(QUERY(A1:100, "Select * WHERE A = 'Australia'"))
But it looks like this logic doesn't work here. Any ideas?
Here is a dummy sheet
P.S.
The second Cumulative column it's just an example of calculations that I'll need to do later with each country numbers. I'll just add =iferror(B3+C2,"0") Although if you have any better ideas on how to optimise that, I'll be happy to hear it.
try:
=QUERY(TRANSPOSE(QUERY(TRANSPOSE(Sheet4!A:AQ),
"where Col1 matches 'Date|Australia|India'", 0)),
"where Col1 >= "&DATEVALUE("2020-1-23")&"
and Col1 <= "&DATEVALUE("2020-1-30"), 1)
and the cumulatives (running totals) can be done like:
=ARRAYFORMULA(IF(O3:O="",,SUMIF(ROW(O3:O), "<="&ROW(O3:O), O3:O)))