I have a table of payments to calculate interest. The column where the payment is applied takes its values from the column where the invoice totals are listed, however, the payment is applied k days after the period ends.
I had partial success doing it using this formula:
IFERROR(INDEX($F$12:$F$25,MATCH(D12,$G$12:$G$25,1)),0)
Where column G is a helper column with the dates of payment, basically period end + k, but since it only accounts for the period end, in monthly and semimonthly periods, sometimes the nearest lower date of payment was on the same period, so I MUST also account for the period start for this to not happen. I've been helped using an array formula like this:
=IFERROR(INDEX(F:F,SMALL(IF(F$12:F12>0,ROW(F$12:F12)),COUNT(1/((C$12:C12-C$12>C$7)+(D$12:D12-C$12>C$7))))),0)
And it works well and it does not require a helper column. But since it's an array formula, and this table is not for my usage, that's not suitable.
I would like to know if I can do this without an array formula and built-in excel 2013 functions.
Edit:
This formula does it:
=SUMPRODUCT(($D$12:$D$25+$C$7>=C12)*($D$12:$D$25+$C$7<=D12)*($F$12:$F$25))
But if there are blanks in column D that result from a formula, it returns an error. So the following formula is more stable:
=SUMIFS($F$12:$F$25,$D$12:$D$25,">="&C12-$C$7,$D$12:$D$25,"<="&D12-$C$7)
This one effectively places the payment rows within the range of dates it belongs to.
At least you can replace SMALL with AGGREGATE like this:
=IFERROR(INDEX(F:F;AGGREGATE(15;6;(ROW(F$12:F12)/(F$12:F12>0));COUNT(1/((C$12:C12-C$12>C$7)+(D$12:D12-C$12>C$7)))));0)
AGGREGATE(15;6;;) is the same as SMALL, but it ignores errors. This lets you switch out the IF(F$12:F12>0,ROW(F$12:F12)) for the quotient (ROW(F$12:F12)/(F$12:F12>0)). Every row-number divided by a FALSE produces an error which gets ignored by AGGREGATE.
For the COUNT-part I cannot say, what it is doing, as my results don't look like yours (i copied your formula).
I guess it works as an offset.
Can you test my formula and tell me if it is working without cse? Else we need to find a replacement for the COUNT-part. I currently cant test it as I am on Office 365 and don't know if i can activate the old CSE-functionality.
Related
I have created a schedule where I am trying to lookup the value of rent for a period of time based on a given date (located in cell B1).
For example, I have the following data set:
Rent Change Date is the date when the rent increases for a specified tenant
Amount is the amount it increases to on the specified Rent Change Date
The schedule off to the right is the monthly rent schedule as dictated by the Rent Change Date
I am currently using a VLOOKUP to identify the range for each tenant using TRUE (or approximate match) to find the rent for the current month (as dictated by the date in B1).
Sample (located in cell G5):
=VLOOKUP(G4, C5:D10, 2, TRUE).
For each tenant, I then reset the table_array range. This works well for a small data set, but I have been searching for a way to set the range automatically. Is there an efficient way to get all of the Rent Change Dates by tenant? Maybe an Excel array formula?
So I'm still not 100% sure I understand what you're looking for, but here is what I came up with.
Using this formula in cell G5 (committing it with Ctrl + Shift + Enter as it's an array formula), and then copying the formula to all other cells in the G5:R7 range, you should get what you're looking for.
Array Formula:
=IF(AND(G$4>=MIN(IF((--($A$5:$A$19=$F5))=0,2,1)*($C$5:$C$19)),G$4<=EOMONTH(MAX(($A$5:$A$19=$F5)*($C$5:$C$19)),11)),INDEX($D$5:$D$19,MATCH($F5&G$4,$A$5:$A$19&$C$5:$C$19,1),1),0)
Example Results:
Result when a tenant is commencing during the year
Result when a tenant is occupied for the whole year
Result when a tenant is expiring during the year
Explanation:
There's a lot going on with this formula, and it's possible there's a simpler way, but I'll do my best to explain. After all, learning isn't just about getting an answer, but also an explanation.
Essentially what you're looking at is a large logical IF function (with three arguments: logical_test, [value_if_true], [value_if_false]). To understand its arguments better, let's break them down:
logical_test
AND(G$4>=MIN(IF((--($A$5:$A$19=$F5))=0,2,1)*($C$5:$C$19)),G$4<=EOMONTH(MAX(($A$5:$A$19=$F5)*($C$5:$C$19)),11))
I started with the AND function because I am attempting to find if a given date (G$4) is either the same as or greater than the first Rent Change Date for a Tenant (this is found using the MIN function) and if the same given date (G$4) is either the same as or less than the end of the month (EOMONTH function) 11 months in the future from the last Rent Change Date for a Tenant.
The embedded IF function within the MIN function is simply there to ensure the correct minimum date is returned. Removing this logical causes the minimum to return 0, which is incorrect for our needs.
I used the EOMONTH function due to the assumption that when the rent changes - including the final rent change - it lasts for a year. Failing to add this piece to the formula would end the rent the same month as the Rent Change Date.
If both statements within the AND function return TRUE, the logical_test then proceeds to the [value_if_true] argument.
[value_if_true]
INDEX($D$5:$D$19,MATCH($F5&G$4,$A$5:$A$19&$C$5:$C$19,1),1)
INDEX(array, row_num, [column_num])
MATCH(lookup_value, lookup_array, [match_type])
COMBINED:
INDEX(array, MATCH(lookup_value, lookup_array, [match_type]), [column_num])
Using the INDEX and MATCH functions together is allowing us to look at the data from any angle without having constraints placed on us. In this case, our array argument - $D$5:$D$19 - spans the entire area of our Amount column. This is where we want to return our value from, so it's important that we cover the full area.
In the place of row_num we use the MATCH function. In our table spanning F4:S8 (which includes the column and row names) we are given both the tenant name ($F5) as well as a reference date (G$4). Combining these with an ampersand (&), we now have a concatenated lookup_value for MATCH. By concatenating these two together, we are increasing the likelihood that our lookup_value is unique and will return us the required information.
If two tenants happen to have the same Rent Change Dates but different names OR if two tenants happen to have the same name but different Rent Change Dates, we will get a unique match; in the rare instance that two tenants share the same name and Rent Change Dates, one tenant will need to have something different to stand out, such as a unit number in the name
Now that we have our lookup_value for MATCH, we need to supply a lookup_array. Given that our lookup_value is a combination of the tenant name ($F5) and a reference date (G$4), we set our lookup_array for MATCH to be a concatenation of $A$5:$A$19 (spans the entire area of our Tenant column) and $C$5:$C$19 (spans the entire area of our Rent Change Date column), joined together with an ampersand (&).
The last argument our MATCH function needs is the [match_type]. For this formula I chose 1 - Less than (Finds the largest value that is less than or equal to lookup_value. The values in the lookup_array argument must be placed in ascending order) due to the fact that we are looking for a date that is either the date itself or one that is less than it as well as the fact that our dates are in ascending order for each Tenant. If we instead looked for an exact match ([match_type] set to 0 - Exact match), we would receive a lot of errors since the Rent Change Dates increase annually, not monthly (like our reference dates in G4:R4). Similarly, looking for a greater than match ([match_type] set to -1 - Greater than) also returns a lot of errors, primarily because the dates aren't in the required descending order.
Closing out of the MATCH function with a ), we return to the [column_num] of the INDEX function from earlier. While this argument is optional with a one-column array, I entered a 1 for clarity. All this means is that once the MATCH function determines which row to grab, I want to get the intersection of [row_num] (which is 1 in the case of G5 using the presented formula along with 2/1/2018 as the date in B1) and [column_num] (1) from the array (the Amount column, $D$5:$D$19). Row 1, Column 1 from the array is $150.00, which is exactly the expected result.
The last piece of our formula is to finish off the IF statement we started with, entering a value for the [value_if_false] argument.
[value_if_false]
0
In the case of this IF function, we simply entered 0 for the [value_if_false] argument. I chose 0 because if the tenant hasn't yet commenced or has expired, we want to reflect a total rent of $0.00 for a given month.
Hopefully this all makes sense and is what you're looking for.
If you create a pivot table based on your data table it can automatically put all the dates across the top row (and you can group by quarter, months, years, days if you so desire).
If you want to search for months, but only have rent rates for years in your source data you may need to use sumproduct. (A pivot table will only include dates where they exist in the source data that I'm aware of, it won't add all dates covered by a range unless explicitly included in that range)
It would like something like below;
=Sumproduct($c$5:$c$300,--($a$5:$a$300=$a2),--($b5:$b$300>b$1),--($b5:$b$300<c$1))
Assumption here is the grid showing data across the top starts from cell a1, and the source data starts from a5.
Because sumproduct effectively is an array formula (you don't need to use Ctrl + shift + enter, it just behaves the same way as an array formula) it's generally not recommended to apply it to a full column for performance reasons.
I am trying to count (or rather to ascribe the number of total orders) of customers based on a) whether they have purchased before, and b) the date of each purchase.
The table also contains all the products ordered in a single order, each in a different line.
Column F is what I'm trying to define (I have filled these numbers in manually and highlighted for clarity).
I am trying to use COUNTIFS:
=COUNTIFS($B$2:$B3,$B3,$A$2:$A3,$A3)
However, I cannot make it work properly.
I need it to count only if
a) the entry in column B is the same as the previous entry, and
b)the date entry (column A) is different then the previous entry. Otherwise, column F should return the same value as the previous entry (so that all 'total orders' for the same email with the same date have the same total orders number.
I think I'm likely missing an 'else' statement somewhere.
Any help is greatly appreciated!
Try this formula:
=IF(B2=B1,IF(A2=A1,D1,D1+1),COUNTIFS(A$2:$A2,A2,B$2:$B2,B2))
Tested below.
In English, the formula checks if emails are equal, then if dates are equal, if so, it grabs value from above. If dates are not equal but emails are it adds one to number from above. If emails are not equal, it starts the count anew with your original COUNTIFS. Because it will always generate a 1 for first row, the structure of the IF blocks work.
I think this would work for you:
=COUNT($A2)+COUNTIFS($A$2:$A2,"<>" & $A2,$B$2:$B2,"=" & $B2)
you can add in operators inside ""s and 'concatenate' with an ampersand (&)
This formula will count any entry above the date given, as long as it is a different date and the same email. I know this is what you were asking for, but it isn't neccesarily accurate as a count of prior purchases. In order for this to be accurate you should consider a different method for recording multiple product purchases on the same date. Otherwise, just label the column "Qty of prior products purchased" as opposed to "Qty of prior purchases. :D GL, speak up if you need anything else!
I have tried to see if this question has been asked before, but I can't seem to find an answer.
I have a column of cells (>3000 rows), with either a value of 1 or 0 (call this column A). The value will depend on the value in column B (which will contain either a value or nothing). The values in column B are a SUMIFS function based, summing from column C, and based on months in column D.
The values in B are paid out on the first business day of the next month. So, the SUMIFS function will calculate the dates that match the last month. This works well in theory, however, not every first business day is the first day of the month. This leads the SUMIFS function to not include everything in the correct month, and allows for some discrepancy, which, when you are dealing with people's money is not great. Further, this discrepancy is compounded across multiple periods (in some cases, there are over 100 periods, and a discrepancy of $1 in period 1 amounts to nearly $1000 in period 100)
What I am wondering is:
Is there any way that I can tell the SUMIFS function (column B) to stop when the value in column A is 0? This would tell the SUM function start the summing from the current value in column B and continue the function to the cell below the preceding value in column B.
I've seen suggestions that the MATCH function may work, but I can't see how to do this with either COUNT or SUM.
For security reasons, this solution needs to be entered into the cell, and can't be VBA. Also, it can't be too large, as it will need to be replicated across 200 worksheets in the workbook (not my file originally, and I would have done it differently, but that is another story). There is no problem entering another column or two if that is required.
Any help is gratefully appreciated.
EDIT:
Unfortunately, I can't post an image of the screenshot. I've included a similar screenshot (columns are not the same layout, but hopefully it gives the idea) here:
Rates calculations
The SUMIF formula is (for B2)
=SUMIFS(C2:C35,D2:D35,D2-1,A2:A35,1)
This works fine if I want all the values in the month, irrelevant of when the payment was made.
However, what I need the formula to do is:
SUM (C2:C35,D2:D35,D2-1, but stop when the first 0 is encountered in A2:A35)
Thanks
The INDEX function can provide a valid cell reference to stop using a MATCH function to find an exact match on 0.
This formula is a bit of a guess as there was no sample data to reference but I believe I have understood your parameters.
=SUMIFS(C2:index(C2:C35, match(0, A2:A35, 0)), D2:index(D2:D35, match(0, A2:A35, 0)), D2-1)
This seems to be something that will stand-alone and not be filled down so I have left the cell addresses relative as per your sample(s).
I am new to Stackoverflow, so please let me know me if there is not enough information. I have had many helpfull insights by using StackOverflow in the past, but I cannot find any helpful thread online, so I hope you can help me.
I've been working on a excel (2013) problem for a while now. I am trying to build a marketing agenda to store and keep track of our mailing campaigns. The campaigns themselves are send via another system, but we miss the ability to plan our mailing campaigns in advance. Since we are active on different markets in Europe, we decided to have a general mailing (for all regions) and a region specific mailing campaign (both are in the same agenda). Besides this we also want to display the mailing focus (different brands). It is my idea to return this as visual as possible (to make it usable for all users). I have add a small picture to show my desired end-result (however without any data at this moment).
At this moment, the users are going to use a (Google)form to enter the campaign information and this data is downloaded to the worksheet (by doing so all users can add new campaigns and everyone always has access to the most recent data). This part works well.
I am using a helper sheet to check if the dates fall in a campaign range, if it does fall in a campaign range it should return the mailing ID (also the row number). I have another form which uses this data to search for the right brand and displays visually (with a lot of conditional formatting).
The problem arises in the helper sheet (when I check if a date fall into a campaign range). I have been able to get it working (more or less) with the following formula:
=IF(SUMPRODUCT(--(CountryHelper!$C$2:$C$100<=$B4);--(CountryHelper!$D$2:$D$100>=$B4);RIJ(CountryHelper!$C$2:$C$100))=0;"";INDEX(CountryHelper!$A$2:$A$100;SOMPRODUCT(--(CountryHelper!$C$2:$C$100<=$B4);--(CountryHelper!$D$2:$D$100>=$B4);ROW(CountryHelper!$A$2:$A$100))))
In this formula, CountryHelper!C:C is referencing the StartDate of the mailing campaing. D:D will reference the column of the EndDates and A:A has the mailing ID. Cell B4 is the date that needs to be checked.
At first it looked this worked perfectly. If a date fell in a date range then it would return the ID. After a little playing around with this a problem came to light. It only works with non overlapping dates, once dates overlap excel will add the row numbers together and it would not work any more.
Is it possible to get the sumproduct formula working and returning only the first ID. I am aware that I then have to make another 2 formulas which return the second and third ID ( I am certain we do not get more than 3 overlapping dates). This is also the part where I get lost. I've tried to use a MIN and MAX variation wit the following sumproduct formula:
=SUMPRODUCT(--(CountryHelper!$C$2:$C$100<=$B4);--(CountryHelper_RSEU!$D$1:$D$100>=$B4);ROW(CountryHelper!$C$1:$C$100))
This will return either a 0 (with MIN) or 100 (With MAX). I think this is caused by the formula (for now it only searches the first 99 rows). I also have ventured into VBA / UDF to get this done, but as I understand it this is not possible.
Anyway, I am sorry for the long story, I hope that my problem is clear and you can help me. If you need any more information.
Thank you!
empty Marketing Agenda overview
The SUMPRODUCT is a kind of swiss army knife Excel function. But here it is wrong because, as you already have seen, it really calculates a SUM at the end. Mostly it works because it first multiplies the 0 or 1 of the conditions with the row numbers so only the row numbers which fulfills the conditions comes into the sum. But if two or more row numbers fulfil the conditions then they were added together.
Are you familiar with array formulas? The following array formula should be what you want:
{=INDEX(CountryHelper!$A$2:$A$100;MIN(IF((CountryHelper!$C$2:$C$100<=$B4)*(CountryHelper!$D$2:$D$100>=$B4);ROW(CountryHelper!$A$2:$A$100)-1)))}
To create a array formula put the formula into the cell without the curly brackets and then press [Ctrl]+[Shift]+[Enter]. Then the curly brackets should appear automaticaly.
How it works:
{IF((CountryHelper!$C$2:$C$100<=$B4)*(CountryHelper!$D$2:$D$100>=$B4);ROW(CountryHelper!$A$2:$A$100)-1)}
Gets a array of row numbers or FALSE {FALSE, rowNumber, FALSE, ...}. If both conditions are fulfilled then it gets the row number - 1, if not then it gets FALSE.
The MIN function then gets the smallest (row number - 1) from this array.
The INDEX then indicates this smallest (row number - 1) which fulfills the conditions.
It subtracts 1 from the row number because your INDEX range starts at row 2. If the row number 2 fulfills the conditions then it is the index 1 within this range, if row number 3 fulfills the conditions, it is the index 2 and so on.
Why it only works as array formula? Because the IF function do not creates a array by default even if their "Value_if_true" is a range. Within the array context it does exact this.
New to VBA, please help. My apologies. I have not done a good job of making myself clear. Let me try one more time.
My sales reps enter every call into a call sheet. They call on 50-60 people a week; some they will see more than once a week, some only a couple of times a year. On this call sheet are 4 columns; date of call, customer, numerical date, and days since last call. This sheet may have hundreds of rows, many are duplicate customers called on a different date.
I have written code that will eliminate duplicates as needed (works fine). New calls are added using NextRow=_ (also works fine). $C$2 is set at TODAY().
Formula in column C is $C10=$A10(Column C is formatted to number). Column D is number of days since last call; $C$2-$C10 etc. Simple and works fine.
Issue is that say I have 50 rows (all different customers) sorted ascending and a new customer is added, key being new. I need the formulas in C and D to drop down one row automatically when the new customer is added. I can drag the formulas down a head of time and everything will work until I sort, then my data is a the bottom of my sort because all rows in column A without a date will produce a 0 in both C and D. My finished product should be a range of different customers (no duplicates); with the customer that has not been called on the longest at the top.
I hope this is a better explanation. Can I write code to ignore the 0's?
I am going to go a little out on a limb here and say maybe your formulas need refactoring...
For instance. If the aim is to calculate the days since the last call was made to a customer, a simple formula such as this would work
=(max(C:C)-Today())
This gets the largest value in column C and subtracts today from it.
If you want to get the value in column D which corresponds to this entry then VLOOKUP() is your friend. you would use it as such:
=VLOOKUP(MAX(C:C),C:D,2,FALSE)
Hope this helps.
Incidentaly, the best way to do your problem in VBA, the simplest way would be to create a Named Range. You can then replace the $C$2-$D11 with the name of the named range. The simplest way to do this would be to say:
Range(Range(C2),Range(C2).End(xlDown)).Name = NAmeOfYourRange
This effectively just gets cell C2, goes to the last non blank cell in the downward direction and names that range NameOfYourRange
Hope this helps :)