In a Google Sheet, I have two sheets, Diary
and Food List
.
The Food List
looks like:
I defined Rice
and Tomato
as named ranges which span from column B to F.
The diary looks like:
I want to add the information associated to each named range, Calory, Fat, ... ., and show them in columns B to F per date.
How can I do that?
1 Answer
Food List
is your lookup table, Diary
has the daily totals by category (eg. cals, fat, carbs, etc.), but you are missing a Food Eaten
table that logs each food item consumed and their weight.
For example, Items Eaten
would need to include at a minimum Date, Food, Portion, but it could also include additional fields such as Time, Notes, Meal, etc.
Food Eaten
is the data that Diary
will total up using the lookup table in Food List
.
Formula
You could use a formula like the following in Diary!A1
to calculate the daily totals:
={"Date", 'Food List'!B1:F1;
SORT(
QUERY(
QUERY(
BYROW('Food Eaten'!A2:C, LAMBDA(r,
{INDEX(r,,1),
IFNA(VLOOKUP(
INDEX(r,,2), 'Food List'!A:F, {2,3,4,5,6})*INDEX(r,,3)/100)})),
"Select Col1, SUM(Col2), SUM(Col3), SUM(Col4), SUM(Col5), SUM(Col6)
Where Col1 is not Null Group by Col1",), "Offset 1",))}
BYROW IFNA INDEX LAMBDA QUERY SORT SUM VLOOKUP
Explanation
- The core of the formula is a BYROW function that passes the range
'Food Eaten'!A2:C
, row by row, into a LAMBDA function that stores the current row inr
. - For each
r
, the LAMBDA's formula returns a single row array where,- Col1 is the value from Col1 of
r
, either a date or an empty value, returned using INDEX. - VLOOKUP is not natively an array function; however, it behaves as one when nested within one (SORT in this case). It returns a 5-column array populated with the values from columns
{2,3,4,5,6}
of the row inFood List
that matches the food in Col 2 ofr
, or empty values if not matched. - A new array is returned by multiplying each value in VLOOKUP's array by Col3 of
r
divided by 100 (per 100g). Again, returning an array is possible only because this calculation is nested within an array function (SORT).
- Col1 is the value from Col1 of
- Once the last
r
has been processed by the LAMBDA, the result is a multi-row array containing populated and empty rows. - QUERY is used to return the SUM of each of Cols2-6, aggregated by date (Col1), including only rows where Col1 is not Null/blank.
- The QUERY's result is nested in another QUERY that uses
Offset 1
to drop the row of labels created by the previous aggregation. - This array is nested in SORT with no arguments which defaults to Col1 ascending.
- Lastly, a label row is added that uses the string
"date"
for Col1, and the labels from Cols2-6 ofFood List
for the remaining columns.
Sample Sheets Data
'Diary'
Formula in A1
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
1 | Date [formula here] |
Calories | Fat g | Protein g | Carbs g | Salt mg |
2 | 2024 October 05 | 717 | 1 | 21 | 160 | 208 |
3 | 2024 October 06 | 408 | 30 | 34 | 1 | 688 |
'Food Eaten'
A | B | C | |
---|---|---|---|
1 | Date | Food | Portion g |
2 | 2024 October 05 | Tomato | 120 |
3 | 2024 October 05 | Rice | 175 |
4 | 2024 October 05 | Dark Rye | 32 |
5 | 2024 October 06 | Egg | 50 |
6 | 2024 October 06 | Tuna | 75 |
7 | 2024 October 06 | Cheddar | 67 |
'Food List' (per 100 g)
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
1 | Name | Calories | Fat g | Protein g | Carbs g | Salt mg |
2 | Cheddar | 406 | 34 | 20 | 1 | 644 |
3 | Dark Rye | 259 | 3 | 8 | 48 | 603 |
4 | Egg | 143 | 13 | 13 | 1 | 142 |
5 | Rice | 350 | - | 10 | 80 | 5 |
6 | Tomato | 18 | - | 1 | 4 | 5 |
7 | Tuna | 86 | 1 | 19 | - | 247 mg |
-
1Thanks! Is there a way to show an error when the eaten food is not found in Food List?– MOONCommented Oct 6 at 16:45
-
1is there a way to show an error when the eaten food is not found" Yes, you'd need to decide whether to display that in Food Eaten and/or Diary and what you actually want to display. eg. Highlight with conditional format, helper column with some value(s), etc. You could try something and if you run into problems post another question.– Blindspots ♦Commented Oct 6 at 17:55
-
Thank you for for explanation! I could not find your explanation in Google Sheet documentation, that is using
Index
orArrayFormula
arround theVlookup
to get an array as output. Could you please point me to the documentation where this is explained so I can learn more on my own? I'v found Google Sheet's doc really disorganized!– MOONCommented Oct 7 at 12:16 -
I updated the answer with an explanation and replaced INDEX with SORT as it's shorter 😉 I'm not aware of Google documentation specifically about this however many non-array functions become array functions in that way. e.g.
INDEX(IF(ISODD(A2:A10),"odd","even"))
I'm resistant to writing ARRAYFORMULA because it is so long. Similarly where possible I'll use,
instead of,0
and1
instead oftrue
etc. There's a lot of undocumented info I've learned from more experienced users on this site.– Blindspots ♦Commented Oct 7 at 14:23