I have a user that is in need of accessing the raw data in a worksheet. We gather numbers throughout the month based on a estimate. At the end of the month the numbers need to be adjusted to the exact total amount. The user more-or-less randomly adjusts some or all of the items until the estimate entered = the exact amount. In other words, I can't just adjust every item by, say, 2% or $50. The user manually goes thru the list of items and assigns adjustments. My question is: can I send the user to the worksheet to make the adjustments and have the user return to the userform that called the worksheet?
Say a month's end we have:
So values were entered in A1 thru A31There is a SUM() formula 8n A32
To perform the adjustment, enter the actual month value in B32 and run this small macro:
Sub dural()
Dim v1 As Long, v2 As Long, delta As Long
v1 = Range("A32").Value
v2 = Range("B32").Value
If v1 = v2 Then Exit Sub
delta = v2 - v1
If delta > 0 Then
For i = 1 To delta
j = Application.WorksheetFunction.RandBetween(1, 31)
Cells(j, 1).Value = Cells(j, 1).Value + 1
Next i
Else
For i = 1 To -delta
j = Application.WorksheetFunction.RandBetween(1, 31)
Cells(j, 1).Value = Cells(j, 1).Value - 1
Next i
End If
End Sub
Results in:
Related
In Excel, I have many products with different sizes listed in columns, such that the sizes "10x10 cm", "11x11 cm" and "15x15 cm" belongs to Product A, etc.
In some other cells, I am selecting a product (either Product A, Product B, or Product C) and a size.
I want, for each of the other products, to determine which size is closest to the selected product:
I don't know how to solve this. One solution might be to remove all non-numeric characters from the strings and add the two values on each side of the "x" and then select the size with the lowest absolute difference from the sum of the selected size.
But I guess it would be easier to do a mapping and use a VLOOKUP to choose the first found size in a given column.
However, the problem is that I do not only have 3 products with a few different sizes, but rather 15 different products with 10 different sizes, so I don't know how to do a mapping in a clever way.
1) Creating a lookup table with the values extracted for each product,
Source sheet:
Code:
Sub lookup()
Dim i As Long, j As Long, prod As Integer, str As String
prod = InputBox("Enter Number of Products")
Sheets.Add.Name = "LookupSheet"
j = 1
For i = 1 To prod
Columns(i).Copy Sheets("LookupSheet").Cells(1, j)
j = j + 2
Next i
For j = 1 To prod * 2 Step 2
For i = 2 To Sheets("LookupSheet").Cells(Rows.Count, j).End(xlUp).Row
str = Replace(Replace(Sheets("LookupSheet").Cells(i, j), " ", ""), "cm", "")
Sheets("LookupSheet").Cells(i, j + 1) = Left(str, InStr(str, "x") - 1) _
* Mid(str, InStr(str, "x") + 1, 999)
Next i
Next j
End Sub
This simple code creates a lookup sheet with the corresponding values. The code ignores any spaces present between the texts.
LookupSheet:
Since you have 15 different products, run this macro to extract the lookup data. This should be a one time activity unless you have additional products.
2) Assuming you enter the product and dimensions to F5 and F6, i would suggest you to data validation with dropdowns to select from the list,
3) Using a worksheet_change event, detect for changes in F5 and F6,
Code:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim str As String, result As Integer, i As Long
'F5 and F6 contains Product and Size repectively
If (Target.Address = "$F$5" Or Target.Address = "$F$6") _
And Range("F5") <> "" And Range("F6") <> "" Then
str = Replace(Replace(Range("F6"), " ", ""), "cm", "")
result = Left(str, InStr(str, "x") - 1) * Mid(str, InStr(str, "x") + 1, 999)
j = 8
For i = 1 To Cells(1, Columns.Count).End(xlToLeft).Column
If Cells(1, i) <> Range("F5") Then
Range("E" & j) = Cells(1, i)
j = j + 1
End If
Next i
End If
End Sub
This code automatically populated the rest of the product types in the column E,
4) The variable result would contain the product/area of the value that you provide in F6. The only task pending would be to loop through the lookup sheet to find the nearest match. The Algorithm is below,
Algorithm:
Compare cell F5 with the data in row 1 of lookup sheet (need to loop)
If they are equal, ignore and move to next value. If not, need to loop the immediate next column to find the next match, and populate the result in the corresponding cell in source sheet.
Algorithm for column wise looping is below,
Steps:
diff = cell.value - result
if diff < 0 then multiply diff by -1
loop:
nextdiff = nextcell.value - result (multiply by -1 if negative)
if nextdiff < diff then
diff = nextdiff
end if
end loop:
The cell value with the least difference would be your best match for that particular product type.
Bit lengthier explanation, hope this helps.
I can't seem to figure out why my code won't work.
I am trying to insert a formula that multiplies a cost by an inflation factor depending on the rating that is inputted. The For loop goes through 7 rows of data in the same column (5), fetches the rating, and assigns a custom formula based on this rating. When I go through the code step by step, the values are all correct and I am able to output the correct equation in a message box. Not sure why I can't post it to the cell though... I think it has something to do with the fact that I'm using Range(Cells(j, 4)) instead of something like Range("D15")
It's important to note that I named some cells Inflation1 through Inflation5.
Ex: If in cell E4 the rating is 2, the code should paste the formula =Inflation2*D4 in cell D15.
Here's the code:
Sub InflationFactor()
Dim CurrentRow As Long
CurrentRow = 4
Dim Rating As Long
Dim j As Long
j = 15
For i = CurrentRow To CurrentRow + 6
Rating = Cells(i, 5).Value
Sheet1.Range(Cells(j, 4)).Formula = "=Inflation" + Str(Rating) + "*D" + Str(i)
i = i + 1
j = j + 1
Next
End Sub
My formula below subtracts a cell until it reaches zero, and moves to the next one. The subtraction is based on the value “B”. Each time the formula comes across the value “B”, this action is performed.
Question: I have been trying to advance this to formulae, in that each time “B” is found that cell is minuses until zero and those amount multiple by the adjacent price.
could you please provide me with a formula which does this ?
Example: when it comes across the first B the full value of 100 x 10 will be multiplied and the reminder 50 will be multiplied by 15 i.e. 50 x 15 price of the next A. These values will be summed.
=MAX(SUMIF($A$2:A2,"A",$B$2:B2)-SUMIF($A$2:$A$10,"B",$B$2:$B$10),0)
The reminder of the 50 is coming from the difference between the B 150 - A 100 , which leaves 50 to be still absorbed .
Further Calculation for explanation:
Apologies thats meant to say calculation of 6000
Your question is still very unclear. What does "My formula below subtracts a cell until it reaches zero" mean? Also, as OldUgly pointed out, it seems that you are ignoring the second A. Since we can't understand each other, take a look at the code below and try to rewrite it yourself to fit your needs. It assumes the data is in a sheet named "Data", and that there is a button (Button1) to run the code.
Dim lLastRow As Long
Dim i As Integer
Dim QtyNumberA, QtyNumberB, QtyNumberRem As Integer
Sub Button1_Click()
lLastRow = Worksheets("Data").Cells(2, 1).End(xlDown).Row 'Rows with data, starting 2nd row (titles in the first)
QtyNumberA = 0 'Variable for storing quantities of A
QtyNumberB = 0 'Variable for storing quantities of B
QtyNumberRem = 0 'Variable for storing quantities remaining
For i = 2 To lLastRow 'scan all rows with data
If (Worksheets("Data").Cells(i, 1).Value = "A") Then
QtyNumberA = QtyNumberA + Worksheets("Data").Cells(i, 2).Value
ElseIf (Worksheets("Data").Cells(i, 1).Value = "B") Then
QtyNumberB = QtyNumberB + Worksheets("Data").Cells(i, 2).Value
QtyNumberRem = QtyNumberA - QtyNumberB
Worksheets("Data").Cells(i, 6) = QtyNumberRem
End If
Next
End Sub
I'm trying to speed up a COUNTIFS formula in a table I have.
The table is over 60k rows and the COUNTIFS has three conditions. The formula right now looks like this:
=IF(AND(COUNTIFS([Vessel],[#Vessel],[Date],">"&[#Date],[ETA],"<="&[#ETA]+20)=0,[#Arrived]=1,[#Sailed]=1,[#Date]<MAX([Date])),1,0)
The problem is that the calculation takes a very long time and it triggers everytime something change, even the filter. I don't want to turn calculations to manual in this sheet.
The purpose of the formula is to find the next occurence of the vessel in the line, the ETA can be slightly changed from day to day or the same ship can appear months later. I need to confirm if the vessel appears with the same ETA (or up to 20 days of difference) on another day.
Is there any other solution to this problem?
Maybe try building this as a macro instead, that way you would have control over when it executes.
Here is a start on a method for doing this. It gets the job done but breaks on an error on/after the last line is processed. Edit : Fixed and tested
Public Sub shipcheck()
Application.ScreenUpdating = False
Dim x As Long
Dim y As String
Dim counter As Long
For x = 2 To Range("A85536").End(xlUp).Row ' Assuming data has headers
y = Cells(x, 1) ' This assumes your vessel is in the first column
counter = x + 1
Do
If cells(counter,1) = "" Then Exit Do
If y = Cells(counter, 1) Then
If Cells(x, 2) <> Cells(counter, 2) Then 'This assumes your date is the second column
If DateDiff("d", Cells(x, 3), Cells(counter, 3)) > 20 Then ' this assumes ETA is your third column
Cells(x, 4) = 1 'This assumes the positive test is the fourth column
Cells(counter, 4) = 1
Exit Do
Else
End If
Else
End If
Else
End If
counter = counter + 1
Loop
Next x
Application.ScreenUpdating = True
End Sub
For example:
695678 needs to be 1
695678 needs to be 1
695678 needs to be 1
695678 needs to be 1
695683 needs to be 2
695683 needs to be 2
695683 needs to be 2
696217 needs to be 3
696217 needs to be 3
I got this list of ID's (every number corresponds to a person) However these numbers for example 695678, 695683, 696217 don't go up by one. They are all ranked from low to high. Is there a way to automatically change these values to 1,2,3,... and so on by changing the lowest value to 1 and the second lowest value to 2 and so on. (can't figure out how to do it with macro's)
One note is that the IDs are repeated as these people made more then one transaction.
thanks!
If you require a VBA solution, then:
Sub Renumber()
Dim N As Long, I As Long, OldValue As Long
Dim K As Long
K = 1
N = Cells(Rows.Count, "A").End(xlUp).Row
OldValue = Cells(1, 1).Value
For I = 1 To N
If Cells(I, 1).Value = OldValue Then
Cells(I, 1).Value = K
Else
OldValue = Cells(I, 1).Value
K = K + 1
Cells(I, 1) = K
End If
Next I
End Sub
#Gary's Student, your solution close to perfect, I've looked into this and added a small correction, Compiling it gives an runtime error, your K value is 1 and in your else clause it just takes the same value again.
After adjusting it to their excel file it worked perfect:
Sub Renumber()
Dim N As Long, I As Long, OldValue As Long
Dim K As Long
K = 1
N = Cells(Rows.Count, 2).End(xlUp).Row
OldValue = Cells(2, 2).Value
For I = 2 To N
If Cells(I, 2).Value = OldValue Then
Cells(I, 2).Value = K
Else
OldValue = Cells(**I + 1**, 2).Value
K = K + 1
Cells(I, 2) = K
End If
Next I
End Sub
The I + 1 between ** is the part that bugged.
I've also changed the cell indexes accordingly.
Kind regards,
David
Please try:
=IF(ISBLANK(A1),1,IF(A1=A2,B1,B1+1))
copied down to suit (with a blank in the top row of data).
To try to clarify, assumes data is in ColumnA but starting in A2 (A1 and B1 being blank), that the formula above is placed in B2 and copied down to suit.
First the test is whether A1 is blank (if True, returns 1 the start point - though this could be keyed into B2 and a simpler formula then used in B3 and so on). If A1 is not blank then there is a further test, whether or not the value has changed. If it has not (True), then use the value immediately above, if it has changed (False) use the value immediately above incremented by one.
Another formula incase your data ever needs to be unsorted, and should be faster then any Macros:
=SUMPRODUCT( (FREQUENCY($A$1:$A$9, $A$1:$A$9) > 0) * (A1 >= $A$1:$A$10) )