How to calculate an average profit per day with Google Sheets - google-apps-script

I made a spreasheet to follow the growth of my income. It include a script that save periodically what I've earned. Column A is DATES, Column B is how much.
I want to calculate my daily average profit.
So I went to substract yesterday to today and then make an average of all that data. But there is a problem along the way because my script is saving data many times a day (to ensure I get data, and to tack more precisely).
I would like to first calculate an average profit for each day individually (C column on screenshot)
Then calculate the variation (D column on screenshot)
Then average the variation. (E column on screenshot)
As my data are growing each day, I'm looking for a flexible way to do it. I think QUERY may be a way but I don't know how to do that. A script would work too I guess. Maybe with the FILTER formula...
What's your thoughts on that ?
Cheers,
NipthiAe.

To calculate the daily profits you shouldn't make an average of the portfolio on each time. For example, if in a single day you have
Portfolio
1
2
3
4
The average would be 2.4 but that's not the day's profits. To calculate a day's profits you need to subtract the last value of the day with the last value of the day before. In this case, if the last value was 0, the answer is 4.
Here is how I would do this.
Solution
Step 1: Find the value of the protfolio when closing the day
What we need to do is find the latest value of each day. The simplest way of doing so is to find the last entry (using the datetime) of the day. So to get the last datetime we can use (in my case added it to D2):
=query({A3:A, arrayformula(int(A3:A))}; "select max(Col1) where Col1 is not null group by Col2 label max(Col1) ''"; 0)
Let's unpack this formula:
{A3:A, arrayformula(int(A3:A))}
It's a 2 column array. The first column are the datetimes. The second column are only the dates. That relies on the fact that int(datetime) returns the number representing the day. Add arrayformula to get it for each datetime and you get the day for each one.
Then the query:
select max(Col1)
where Col1 is not null
group by Col2
order by max(Col1)
label max(Col1) ''
The trick here is to get the biggest (latest) datetime within a day. This can be achieved by selecting max(datetime) and grouping by date. Then we can add a filter for empty cells (where Col1 is not null) and order the result to ensure the correct ordering. Also remove the default label by adding label max(Col1) '' at the end.
Step 2: Get the last value
Now that we have the last datetime of the day we can use vlookup to get the value (on E3):
=arrayformula(if(D3:D<>""; vlookup(D3:D; A3:B; 2; false); ""))
As you can see it's a simple vlookup that was wrapped in an if to prevent getting an error on empty cells. arrayformula allows us to do it for each row in one formula.
Step 3: Getting the daily profit
Now that we have the latest value we only need to subtract the row with the previous one (on F3):
=arrayformula(if(E3:E100<>""; E3:E-offset(E3:E; -1; 0); ""))
offset allows us to use this formula without having to specify the number of rows. As always, arrayformula allows us to do it for all rows in a single formula and we filter empty rows.
Step 3: Total average
We can finally take the average:
=average(F3:F)
If you didn't start from 0, you should change it to start at the next value (F4) since the first value will be the accumulated until that point.
References
QUERY (Google Editors Help)
VLOOKUP (Google Editors Help)
ARRAYFORMULA (Google Editors Help)
OFFSET (Google Editors Help)
IF (Google Editors Help)
INT (Google Editors Help)

You can do it with 3 formulas:
First (query) in D2:
To get the average per day
=query({A2:B},
"Select Col1 ,count(Col1), avg(Col2) where Col1 is not null
group by Col1 Order By Col1 asc
label Col1 'Date', count(Col1) 'Days', avg(Col2) 'Average/day'")
Second in G4:
To get the differences between the averages obtained by the Query:
=arrayformula(if(isblank(E4:E6),"",filter(E4:E6,E4:E6>-1)-filter(E3:E6,E3:E6>-1)))
Third (above the query) in F1:
To get the average of the variations:
="Variation Avg: "& DOLLAR(round(AVERAGE(F3:F),2))

Related

SUM Function to count values in multiple rows in a date range

Hoping to get some help on a rather interesting formula!
Column A = Start Date
Column B = End Date
Column C = # Sales
Goal: create a calculator on the same sheet that allows me to input two dates (Start Date/End Date), and have the output be the sum of all values in Column C within that defined range (see image).
Problem: figuring out a way to have the formula recognize and sum the data in between the rows that are within the data range but not directly equal to the values that define the range (in other words, I can only figure out formulas that sum the first and last rows of the array)
Thanks in advance!! Here's the link to a sample spreadsheet with sample data: https://docs.google.com/spreadsheets/d/1d3fKGXdvVPFJNJA-TgHbH7t250GS2pQQCWvQC31T5Ow/edit#gid=0
use:
=SUMIFS(C2:C, A2:A, ">="&E3, B2:B, "<"&F3)
Another option if you want to write SQL:
=QUERY(
A:C,
"
SELECT
SUM(C)
WHERE
A >= DATE '"&TEXT(E3, "yyyy-mm-dd")&"'
AND B < DATE '"&TEXT(F3, "yyyy-mm-dd")&"'
LABEL
SUM(C) ''
"
, 1)
You can also try using FILTER in combination with sum.
I find this approach nicer since the SUMIFS has some strange shorthand.
=SUM(FILTER(C2:C14,A2:A14>=E3,B2:B14<F3))
If you use filter you might have an extra column saying the city (e.g. column D would be Dallas or Copenhagen), and then you could filter that also. In your case you would add to the filter, D2:D14="Dallas".
I put the code in your shared sheet.
Cheers Mads

SSRS - match dataset values with hard-coded values

I am trying to create an RDL file and I need a tablix to appear in the following format.
This is how I want the results to look
The values that are in bold are hard coded values. This is how the output from the SELECT statement in the datasets looks
SQL Output
I don't know how to make the values that output from the database match with the hard coded values in the RDL file. The 'Day' field represents a day in the month and the 'Num' field represents the number of sales that were on the day. The above example shows that on the first day of the month, there were 100 sales made. I need the tablix to output in that specific format.
If the day isn't in the SQL output (no sales made that day), I want it to output blank and/or 0.
Any idea how this could be accomplished?
Use a CTE to create rows for each day you need and then join your results on. A starting point for you CTE could be:
;WITH nums AS
(SELECT 1 AS value
UNION ALL
SELECT value + 1 AS value
FROM nums
WHERE nums.value <= 30)
SELECT *
FROM nums
You'll probably then want to modify the total days based on the month you are viewing.
You can do this using lookups, but you would need to hard code a lookup in each cell. e.g. for day 1
=lookup(cint(1),Fields!Day.Value,Fields!Num.Value,"Dataset1")
A faster way would be to create a tablix on the dataset filtered on the first ten days:
=Switch(
Fields!DAY.Value <= 10 and Fields!DAY.Value >=1,"Include",
True,"Exclude"
)
Create a row group on days, then create a column with day and num, and columns with Fields!DAY.Value+10 and Fields!DAY.Value+20 with the following lookups:
=lookup(Fields!DAY.Value+10,Fields!DAY.Value,Fields!NUM.Value,"DataSet1")
=lookup(Fields!DAY.Value+20,Fields!DAY.Value,Fields!NUM.Value,"DataSet1")

mysql - calculating columns(2 columns with numbers) based on another group of column(text)

Hi I would like to find a query for the below, I am trying to calculate data between two columns however based on another column which needs to be a selected group of the same values
Unfiltered
Start Time________Disconnect Time______Signalling IP
12:59:00.3________13:26:03.3___________1.1.1.1
10:59:00.3________11:03:03.3___________2.2.2.2
19:59:00.3________20:02:03.3___________1.1.1.1
Filtered
Start Time________Disconnect Time______Signalling IP
12:59:00.3________13:26:03.3___________1.1.1.1
19:59:00.3________20:02:03.3___________1.1.1.1
If you see the table above, I want the selected IP only which is 1.1.1.1, and then from there, calculate the total duration of time from the Start Time and Disconnect Time for that Egress IP.
So column 3 has multiple values, however I need to select the same value, then from there calculate the sum of column 1 and 2 based on column 3.
Please let me know if you have anything in mind, as I have tried multiple queries but can't get the correct one
to calculate difference between to times.
you can use time_to_sec to convert each time value to seconds
and subtract start time from end time to get time period in seconds.
you cat turn it back to time format with SEC_TO_TIME
example
select
column3,
SEC_TO_TIME(sum(TIME_TO_SEC(column2) - TIME_TO_SEC(column1))
from
table
group by column3

mysql get data from a specific week [duplicate]

I am having a table as follows in MYSQL:
proj_id|hoursWorked|Date.
The date field is of type Date; I want to retrieve all the entries from a table depending on a given week number for the project in my java based web application. Please help me to achieve this.
I am unable to write a single query that will allow me to do so.
Do not use something like WHERE WEEK(column)=something - this is a performance killer: It will calculate the week number on all rows, even if they don't match. In addition to that it will make it impossible to use an index ont this column.
Instead calculate an absolute begin and end date or point in time, depending on your data type, then use BETWEEN. This will do no calculations on non-matching rows and allow the use of an index.
Rule of thumb: If you have the choice between a calculation on a constant and on a field, use the former.
use MySQL WEEK() function.
SELECT WEEK(dateColumn)
FROM...
WHERE WEEK(dateColumn) = 1
WEEK()
from MySQL Docs
This function returns the week number for date. The two-argument form
of WEEK() enables you to specify whether the week starts on Sunday or
Monday and whether the return value should be in the range from 0 to
53 or from 1 to 53.
Use WEEK
select * from your_table
where week(`Date`) = week('2012-12-01')
If you want to get only records from the current week you can do
select * from your_table
where week(`Date`) = week(curdate())

MySQL - Find date ranges matching a list of months

I have several rows in a table, each containing a start date and an end date. The user has a checkbox for each month of the year. I need to determine which rows contain a date range that includes any of the user's chosen months.
It's easy to check the start & end months by, for example, MONTH(start_date) IN ($month_list), but this approach won't match any months between the two dates.
So I suppose what I'm asking is: is there a way of obtaining the inclusive months from a date range purely in SQL?
I assume you would want to include data rows where the date range spans or intersects with the selected periods - in which case, I'd shove the user selected periods into a table and do a fuzzy join, something like.....
SELECT DISTINCT at.*
FROM a_table at, user_periods up
WHERE at.start_date<=up.end_date
AND at.end_date>=up.start_date
AND up.trans_id=$SOME_VAR
(the trans_id just allows the table to be used for multiple operations)
To minimise the effort here, the user_periods table should have an index on start_date and end_date, and similar for a_table.
Can something like this help?
WHERE
MONTH(start_date) < MONTH_YOU_ARE_CHECKING and
MONTH() > MONTH_YOU_ARE_CHECKING
If you need to check all at once you can do a list of all the months and after delete from the list the month that the user choose, and after compare against the list. It will be better with a pseudocode example :)
MONTHS = 1,2,3,4,5,6,7,8,9,10,11,12
USER_SELECTED_MONTHS= 1,6,8,9,12
LIST_TO CHECK = 2,3,4,5,7,10,11
so, now you can do:
MONTH(start_date) NOT IN (2,3,4,5,7,10,11)
What do you think, could it help you?
regards