I have a budgeting spreadsheet where I am trying to get the sum of cells in col A if the string in Col B is a certain keyword. For example, one of my formulas is =SUMIF(D13:D36,"Restaurant",C13:C36), so if any of cells in Col D are Restaurant, it takes the amount in Col C and adds them up. I have about 10 of the same formula, each with a unique string/keyword. This function works fine.
My problem is when I add a lot of entries and my columns get longer than the code specifies, I need to go into each formula separately and update the cells (eg, change C13:C36 to C13:C45, but 10 times).
If I enter "C13" into a cell, for this example T1, is it possible to call the contents in cell T1 within the SUMIF function? So the function would look something like =SUMIF(D13:D36,"Restaurant",CELL(T1):C36). I know the CELL function doesn't work here but is there something that could?
What I am trying to do is write the start and ending cells somewhere in my sheet then call them inside the SUMIF function, so if I need to change them later I only need to update 4 cells rather than 10+.
First as stated in the comments, there is no cost to using full columns:
=SUMIF(D:D,"Restaurant",C:C)
Which now it does not matter how large it gets.
excel
But if one wants to limit it using other cells, I would use INDEX, instead of INDIRECT as INDIRECT is volatile(This only works in Excel):
=SUMIF(INDEX(D:D,T1):INDEX(D:D,T2),"Restaurant",INDEX(C:C,T1):INDEX(C:C,T2))
Where Cell T1 holds the start row and T2 holds the end row.
you could use simple QUERY like:
=QUERY({C13:D}, "select Col2, sum(Col1)
where Col2 matches 'Restaurant'
group by Col2
label sum(Col1)''", 0)
or for the whole group:
=QUERY({C13:D}, "select Col2, sum(Col1)
where Col2 is not null
group by Col2
label sum(Col1)''", 0)
Related
You will need this solve this.
In this sheet, I am trying to take the scores of the people and log them in the "Week Total" Column L as a sum. The names often exist in each column for that days score. I need to take their score for each day next to their name, and log it next to their name in Column L as a total if that makes sense.
So if Bob got a 10 on Monday, a 10 on Tuesday, and X the rest of the days, then I need to log that in Column L next to his name as "20".
I am using the Unique function to log all their names under Column K.
Thank you!
You can use query and combine it with some array notations.
Formula:
=query({{A4:A,B4:B};{C4:C,D4:D};{E4:E,F4:F};{G4:G,H4:H};{I4:I,J4:J}}, "select Col1, sum(Col2) where Col1 is not null group by Col1 label sum(Col2) ''", 0)
Output:
Note:
A duplicate Bob can be seen as you have spaces after Bob on some cells (e.g. Bob ). Make sure to have no spaces with them when inputting to remove duplicates from the formula result, or just use trim before using them. See modified formula before:
Formula with trim:
=query(index({{trim(A4:A),B4:B};{trim(C4:C),D4:D};{trim(E4:E),F4:F};{trim(G4:G),H4:H};{trim(I4:I),J4:J}}), "select Col1, sum(Col2) where Col1 is not null group by Col1 label sum(Col2) ''", 0)
Result:
You're not making your life easier by inputting X since that will be read as text, I'd recommend using 0 instead (if you insist on X then add an IF statement to exclude the Xs).
But what you're looking for is =SUMIF() coupled with some smart Array notation as demonstrated here in the documentation.
Create arrays
You can also create your own arrays in a formula in your spreadsheet by using brackets { }. The brackets allow you to group together values, while you use the following punctuation to determine which order the values are displayed in:
Commas: Separate columns to help you write a row of data in an array. For example, ={1, 2} would place the number 1 in the first cell and the number 2 in the cell to the right in a new column.
Semicolons: Separate rows to help you write a column of data in an array. For example, ={1; 2} would place the number 1 in the first cell and the number 2 in the cell below in a new row.
Note: For countries that use commas as decimal separators (for example €1,00), commas would be replaced by backslashes () when creating arrays.
You can join multiple ranges into one continuous range using this same punctuation. For example, to combine values from A1-A10 with the values from D1-D10, you can use the following formula to create a range in a continuous column: ={A1:A10; D1:D10}.
Adding arrays to existing formulas
You can also use arrays with other existing formulas using brackets in order to organize the returns from your formulas into rows or columns.
For example, ={SUM(A1:A10), SUM(B1:B10)} will produce two values. The first cell will contain the sum of A1 to A10, the cell to the right will contain the sum of B1 to B10.
My tablix groups on one of its columns and only needs to output a list of time stamps for each row. As the time stamps are only two columns, that leaves an awful lot of wasted space.
Here is a basic mock-up of the current layout...
... and this is the desired layout:
As shown, the report would ideally adjust dynamically to display half the rows of a group in the left "column" (including the extra row if uneven) and the remaining rows in the right "column". Is this possible with SSRS? If not as described, can you suggest something with a similar result?
You can do this with as long as your dataset can be updated to support it.
First I grabbed some sample datetime data I had and inserted it into a table variable called #t. You'll just need to swap out #t for your actual table name. This gave me the following
Then I take this data and workout the row and column the data should sit in. In this example I am using a parameter to define the number of columns I want. You could do this and pass it in from your report if it's helpful, or just change it to a staic value. I'll demo with the parameter being passed in though.
Here's the query (Note you'll need to comment out the #Columns declaration if you want to pass this in from your report but for now we are just testing in SSMS or similar.
-- REPLACE #t with your actual tablename below
DECLARE #Columns int = 2 -- <= comment this out when you copy into your dataset query
SELECT
*
, ColumnNum = ((SortOrder-1) % #Columns) + 1
, RowNum = ROW_NUMBER() OVER(PARTITION BY GroupID, SortOrder % #Columns ORDER BY SortOrder)
FROM(
SELECT
ROW_NUMBER() OVER(PARTITION BY GroupID ORDER BY dt) as SortOrder,
GroupID, dt
FROM #t) x
ORDER BY GroupID, SortOrder
This gives us the following output
Now all we have to do is use a matrix control in the report to display it correctly.
Create a new report
Add a datsource and dataset
Set your dataset query as above remember to comment out the DECLARE #Columns line if you want to parameterise it.
Add a matrix control
Drag RowNum to the 'Rows' placeholder, dt to the 'data' placeholder and finally select ColNum in the columns placeholder
The matrix should look like this (we're not finished yet...)
In the row groups panel, drag GroupID above the exiting row group (above rownum in my example) so it creates a parent group.
Finally, add a blank row inside the RowGroup group by right-clicking the rownum textbox and doing "Insert Row, Inside Group - Below". This will just give us a gap between groups
Note: I've changed the colour of the rownum and columnnum text boxes as we can delete these once testing is complete.
The final design should look like this.
When we run the report and set the parameter to 2 we get this
set it to 3 and we get this
You can now remove the top row and middle column to get rid of the row and column numbers. If you want to have a group header as in your sample. Add a row inside the group again but this time at the top and then add an expression to give your desired title.
I got a sum Table 1 from a dataset, grouped by a parent Group 1 and a child group 2.For C, it sums values for different Sites.
The table I really want is to merge the SumValue under one column and re-name the group, e.g., C1 & C2 instead of Site-C1 & Site-C2.
I have tried to rename the Group 2 from Site_C1 and Site_C2 to C1 and C2, but it still splits to different columns:
Thank you for your help in advance.
It is similar to a question you posted before. As I said in that moment you can use an expression to conditionally set the grouping settings in your matrix. Add a matrix and add the Group 1 to Column Groups
In the Group properties / Group on put this expression:
=IIF(
Fields!Group.Value="C",
RIGHT(Fields!Subgroup2.Value,2),
Fields!Group.Value
)
Note Subgroup2 is Group 2 in your case.
Put the same expression on the header (the selected cell in the screenshot). It will preview the following matrix:
Let me know if this helps.
I would add one ore more calculated field to the dataset. There you can add the values of the relevant columns like this:
=IIF(IsNothing(Fields!C10.Value), 0,Fields!C10.Value)
+ IIF(IsNothing(Fields!C11.Value), 0,Fields!C11.Value)
+ IIF(IsNothing(Fields!C11.Value), 0,Fields!C12.Value)
In your table, don't bind a column to C10, C11.. but bind it to the calculated field.
I have edited my question and replace the previous explanation with new one.
I think I could't explain my problem clearly before. here is my scenario:
Col1 |Col2 |Col3 |Col4 |Col5 | Col6
------|------|------|-------|------| 3333.00 (Table 1)
------|------|------| 15.00| 0.00| 3348.00 (Table 2)
------|------|------| 0.00|550.00| 2798.00 (Table 2)
Sub ToTal:-----| 15.00|550.00| 2798.00 (Table 3)
In this report value (3,333.00) of Table 1 is Opening Balance. For Table2 and Table3, col4 is Deposit and Col5 is Withdraw. Last column of Table2 and Table3 are closing balance. So, the rule is, closing balance of first row of Table2 should be calculated as (ClosingBalance = OpeningBalance + Deposit - Withdrawal). and Closing Balance of 1st row should be opening Balance for second row. Table 3 has nothing to do with them.
Now problem is that 3333.00 is coming from query so we can easily calculate 3348.00 but i dont know how to calculate 2798.00 as it required value of above cell which is 3348.00. similarly if Table 2 generate 10 rows than 1st value of last column should be calculated from 3333.00 and remaining rows will calculate their values from above cell i.e 2798.00 depends on 3348.00 and if there is next row than it will depend on 2798.00. so i have done this:
IIf(RowNumber(DatasetName) = 1, value of Table1(3333.00) + and remaining values to calculate 3348.00, Previous(ReportItems!MyTextBoxName.Value) + other values)
Now it gives me error:
The Value expression for the textrun 'Amount8.Paragraphs[0].TextRuns[0]' uses an aggregate function on a report item. Aggregate functions can be used only on report items contained in page headers and footers.
I searched over different forums and found out that I can't use ReportItems in this scenario. So, what should I do?
I know my scenario is complicated and its more complicated to explain it but I tried my best. Please tell me any solution you have.
Try Previous(Copy the expression used in your MyTextboxName)
You can use Lag function in your SQL Statement to get to previous value.
SELECT Field1, Lag(Field1,1,NULL) OVER(PARTITION BY .... ORDER BY ....)
FROM Table1.....
Here are couple of articles to help you understand Lag in Detail
Intro to Lead and Lag By Pinal Dave
Lead and Lag function article in DatabaseJournal
I need to generate a result set in two steps. The first step is simple and generates a base in-memory result set (let's call it B). In the second step, I need to add an additional column to B (let's call it c). For each row in B, c can be calculated by using an aggregate function on B based on the values of that row (this does look inefficient though).
The final result set is B + c. Results must be sorted by a column from B as well as the c column, so the whole thing should be a single query.
Getting B is simple, but how do I process it further based on its contents?
EDIT. Here's a table analogy to illustrate what I mean by "applying an aggregate function on B based on each row in B":
Say, we have a table T with a column col. Let's say that for each row in T we want to calculate the number of rows that have a higher col value. You could do it like this:
select
t1.*,
(select sum(case when t2.col > t1.col then 1 else 0 end) from T t2) as count
from T t1
In my case the problem is that B is not a real table but an in-memory result set. How can I process it in a similar way?
OK - I'll give it another go.
Aliasing both the in memory results set and the columns that you need to use in that results set to derive c should work.
To continue your example from above:
select B.col,
(select sum(case when B2.col > B.col then 1 else 0 end) from (select whatever_col as col
from whatever_table) B2) as c
from
(select whatever_col as col from whatever_table) as B;
Let me know if I've got the wrong end of the stick again!