Subtract two columns, with each other as a condition, and append values - vba

I need to subtract two columns from a large array and see which ones are positive and of those positive values I need to find the positive values row and append a few things onto that value.
Here is the general concept I'm thinking so far
While < 8000
if (cell(i,1).Value - cell(i,2) > 0)
print in another sheet cell(i,3).value (cell(i,2).Value-cell(i,4)) cell.value(i,4)
for example...
suppose I have something like this
[2 2 hi yo]
[3 2 go mo]
this macro would return "go 1 mo" in another sheet.
Sub Leaves()
Dim i As Integer
Dim g As Integer
Dim Quantity As Integer
Dim Executed As Integer
Dim Leaves As Integer
i = 1
g = 1
Do While i < 8000
Quantity = Worksheets("Sheet1").Cells(i, 3).value
Executed = Worksheets("Sheet1").Cells(i, 5).value
Leaves = Quantity - Executed
If Leaves > 0 Then
Worksheets("Sheet2").Cells(g, 1).value = _
Worksheets("Sheet1").Cells(i, 9).value & _
Worksheets("Sheet2").Cells(i, 2).value & _
Leaves & Worksheets("Sheet2").Cells(i, 3).value
g = g + 1
End If
i = i + 1
Loop
End Sub
The above code gives me a Type mismatch error.

It is helpful if you say what line is throwing an error. Also, one should strive to create a Minimal, complete, and verifiable example. The effort to do so often resolves the question before you need to post it.
The code itself seems fine and it runs for me (on an empty workbook) with no type mismatch. Thus, the problem must be with your assumptions about the spreadsheet.
Either of the lines
Quantity = Worksheets("Sheet1").Cells(i, 3).value
Executed = Worksheets("Sheet1").Cells(i, 5).value
will trigger a type mismatch if the corresponding value can't be converted to an integer. This could happen, for example, if one of the cells contains a string (other than something like "1") or an error value such as #N/A or #Value!.
The line which begins
Worksheets("Sheet2").Cells(g, 1).value = _
will throw a type mismatch if one of the values being concatenated can't be converted to a string. An error value in one of the cells is the most likely culprit. If this is the case and for some reason you actually want to create a string that includes substrings which look like e.g. "#N/A" then you could use the Text property of those cells rather than Value.

Related

Dynamic Named Range with Moving Data Below

I am trying to create a dynamic named range that I can use for a data validation list. I use these all time but in this case I have information that is housed below the range that cannot be counted in the range. Also, I have a macro that insert rows within this range that do need to be counted.
I normally would use something like this if nothing else was in the column: =OFFSET($A$1,0,0,COUNTA($A:$A),1)
I need to start this one down the page a little ways so I used:
=OFFSET($A$24,0,0,COUNTA($A$24:$A24),1)
Notice I have removed the "$" before the last "24" in the formula hoping it would expand accordingly, but that does not seem to be consistent.
Basically, I need the COUNTA range to only include a range of cells that will always be growing and shrinking.
I'm not bad in VBA and am open to a solution that might include looping through a range of cells and stopping once it reaches a cell that's value equals a certain text string (in the case in would be .Value = "Request 1"). But I am a little apprehensive about feeding a form or ActiveX Control, as this has caused me issues in the past with viewing and printing functionality.
I used a the following code to create a range elsewhere in the workbook that I could then easily use to create a dynamic named range:
Sub UpdateEntities()
Dim i As Long, x As Long
i = 24
x = 1
Sheets("Values").Range("AH:AH").ClearContents
Do While Cells(i, 1).Value <> "REQUEST 1"
Cells(i, 1).Select
If ActiveCell.Value <> "" Then
Sheets("Values").Cells(x, 34).Value = ActiveCell.Value
i = i + 1
x = x + 1
Else
i = i + 1
End If
Loop
End Sub

Comparing values of cells in a column with ComboBox value input by user

I am not able to compare the values of a cells in a column with combobox value input.
I have 2 workbooks tests(contains ComboBox2) and test1(contains a column whose cells are compared with ComboBox2.value)
I have a for loop to achieve this.
For i = 1 To LastRow
If wkbSource.Worksheets(sheet_no).Cells(i, 1) = ComboBox2.Value Then
'do something
End If
Next i
I have debugged the code and I understood that if statement doesn't execute even after a match.
How can I fix it ?
EDIT :
Also I would like to know how you can add two cell values because directly adding it is showing incorrect output.
For example
wkbSource.Worksheets(sheet_no).Cells(i, 1) + wkbSource.Worksheets(sheet_no).Cells(i, 3)
This was due (once again) to the Variant Comparison Curse. See in particular the "UPDATE 4" of that question.
If wkbSource.Worksheets(sheet_no).Cells(i, 1) = ComboBox2.Value Then
This compares two Variants. But, when the cell contains a number, and is not explictly formatted as Text, not preceded by ' when entered. Excel will consider it as a number and so it's .Value will be a number Variant. On the other hand, Combobox2.Value retuned a text Variant, so the comparison failed!
When comparing two Variant variables, these operations will fail:
2 = "2" ' False
3 > "2" ' False
Therefore, the solution in your particular situation is to force comparing texts, using the .Text properties of the control and the cell. Here's how you would - for example - sum up cells that match your query:
For i = 1 To LastRow
If Trim(wkbSource.Worksheets(sheet_no).Cells(i, 1).Text) = Trim(ComboBox2.Text) Then
'do something
if IsNumeric(wkbSource.Worksheets(sheet_no).Cells(i, 1).Value2) Then _
mySum = mySum + wkbSource.Worksheets(sheet_no).Cells(i, 1).Value2
End If
Next i

Add a new column in excel without changing the VB code

I create a VB program to automatically update a Gantt chart for a group project. But now the team wants to add a new colum. The problem is that adding a new column will change my code and make it unusable. Rows can be added without changing the code, but I would have to update all my code if new colums are added. How can I add a column without chaning my VB code?
Private Sub Worksheet_Change(ByVal Target As Range)
Dim StartDate_Row As Integer
Dim Total_Weeks As Integer
Dim Date_Week_Column As Integer
Dim Number_of_Weeks As Integer
Dim Date_Week_Column_Color As Integer
StartDate_Row = 10
Date_Week_Column = 8
Range("H9:AN25").Interior.Color = xlNone
Do
For Total_Weeks = 1 To 33
If Cells(StartDate_Row, 5).Value = Cells(8, Date_Week_Column).Value Then
Date_Week_Column_Color = Date_Week_Column
For Number_of_Weeks = 1 To Cells(StartDate_Row, 6).Value
If Cells(StartDate_Row, 7).Value = 25 Then
Cells(StartDate_Row, Date_Week_Column_Color).Interior.Color = RGB(204, 255, 299)
End If
If Cells(StartDate_Row, 7).Value = 50 Then
Cells(StartDate_Row, Date_Week_Column_Color).Interior.Color = RGB(153, 255, 204)
End If
If Cells(StartDate_Row, 7).Value = 75 Then
Cells(StartDate_Row, Date_Week_Column_Color).Interior.Color = RGB(102, 255, 178)
End If
If Cells(StartDate_Row, 7).Value = 100 Then
Cells(StartDate_Row, Date_Week_Column_Color).Interior.Color = RGB(50, 200, 100)
End If
If Cells(StartDate_Row, 7).Value = 0 Then
Cells(StartDate_Row, Date_Week_Column_Color).Interior.Color = RGB(149, 179, 215)
End If
Date_Week_Column_Color = Date_Week_Column_Color + 1
Next Number_of_Weeks
End If
Date_Week_Column = Date_Week_Column + 1
Next Total_Weeks
Date_Week_Column = 8
StartDate_Row = StartDate_Row + 1
Loop While (Not IsEmpty(Cells(StartDate_Row, 5)))
End Sub
Tom's suggestion is a possibility but is a lot of bother for the user for every run of your macro.
Possible technique 1
I never refer to columns or rows by numbers for two reasons:
Columns and rows may move as you have discovered.
Someone reading your code must know what column 5 or row 6 means.
It is better to use constants. Fo example:
Const ColXxxx As Long = 5
Const RowYyyy As Long = 8
If Cells(StartDate_Row, ColXxxx).Value = Cells(RowYyyy, Date_Week_Column).Value Then
I do not know what your rows and columns are so I have used ColXxxx and RowYyyy as names. You would replace my names with names that tells the reader what the row and column are.
Code like this takes a little longer to write but (1) it is self documenting and (2) if a column or row moves, you only need to change the Const statement to fix the problem.
Note: I have used data type Long. Data type Integer defines a 16-bit variable which requires special (slow) processing on 32-bit and 64-bit computers.
Possible technique 2
Technique 1 requires the user to tell the programmer that they want to add a column or move a row. If they forget to tell the programmer before runnibg the macro with an amended worksheet, the macro may damage the worksheet beyond repair.
Another technique is to search row 1 for the know column headings and record where there are. Pehaps you have a column heading "Start Date". "Start Date" can be in column 5 for one run of the macro and in column 6 for the next and you code will work just as it should.
If this technique is interesting, I will add example code.
The answer in short is that you must change your code. This becomes a bigger and bigger issue the larger and more complicated your code becomes. Therefore where possible try to think dynamically about the methods you use to specify cell locations.
E.g. You could build into your script a user input which allows the user to specify the column which contains the required information. That way if the user adds more columns to the table, the script will still run correctly (provided the user selects the correct column).
'ask user to select the column containing the data which they would like to utilise
Dim colRng As Range
On Error Resume Next
Set colRng = Application.InputBox("Select a cell from anywhere in the column which contains the programme start dates.", Default:="", Type:=8)
On Error GoTo 0
If colRng Is Nothing Then
'notify user that the process cannot continue as selection was invalid
MsgBox "You must select a cell to enable this process to continue!"
'exit the sub
Exit Sub
End If
'output the column number (as selected by the user)
debug.print colRng.column
Hope that helps!
If you define a named range on your worksheet (using Formulas > Define Name), that name will be updated to point to the same cell(s) even if rows and columns are inserted or deleted.
In your code you can use (for example) MySheet.[MyRangeName].Row to get the row number of the first row of the range named MyRangeName, and so on.

Excel VBA Match function not working

I'm using INDEX and MATCH functions to pull data which is concatenated string of G2 and H2 from column D (sorry I don't have enough points to attach pic). Column D has INDEX(column A and column B) and columns A and B have values till 12th row. MATCH is working fine giving me the position as 6 on the worksheet. But when I use this in VBA code as shown below,INDEX is working in the VBA code (can be seen through MsgBox) but MATCH function which would allot value to the variable 'check' isn't working. I have been breaking my head for really long. Need help from experts here. Somebody please tell me where am I going wrong?
Sub testindex()
Dim check As Long
Set sh = Sheets("Sheet1")
For j = 1 To 11
'Index value is correctly shown
MsgBox "Index Value=" & Application.WorksheetFunction.Index(sh.Range("A2:B12"), j, 1) & Application.WorksheetFunction.Index(sh.Range("A2:B12"), j, 2)
'Cells(7, 4)=ISA737775 same as G2&H2
MsgBox "Cells(7,4)=" & Cells(7, 4)
check = Application.WorksheetFunction.Match(Cells(7, 4), Application.WorksheetFunction.Index(sh.Range("A2:B12"), j, 1) & Application.WorksheetFunction.Index(sh.Range("A2:B12"), j, 2), 0)
Next j
End Sub
Thanks
Match expects the second paramater to be in the form of a range. When you call match through VBA that range actually needs to be a range object, not just some string like "A1:A12" or whatever it is that your concatenated Index formulas output.
At any rate, you are iterating already, so why not just call those values directly instead of pulling their values through Index?
check = Application.WorksheetFunction.Match(Cells(7, 4), sh.Range("A" & 2 + j).value & sh.Range("B" & 2 + j), 0)
Which is writing the same exact thing but without having to use a taxing INDEX function in VBA to do it. Note that this still won't work because the second parameter of match is still just a string which is a concatenated value from Column A and Column B. You could convert to a range by sticking them in the range object with:
check = Application.WorksheetFunction.Match(Cells(7, 4), sh.Range(sh.Range("A" & 2 + j).value & sh.Range("B" & 2 + j)), 0)
I'm assuming that the values in A and B are actual cell names that when concatenated will make a range. Like when j=1 then the it would be like check=Match(Cells(7,4), sh.Range("G2:H50"), 0) or something...

numbers of unique entries in range, VBA

I always receive type missmatch errors or division by zero errors while trying to implement following: I just want to count the number of unique entries in a range, the entries in the range are of "class" text:
startRow = 3
startColumn = 1
col = "A"
Set topCell = Cells(startRow, startColumn)
Set bottomCell = Cells(Rows.Count, startColumn)
If IsEmpty(bottomCell) Then Set bottomCell = bottomCell.End(xlUp)
Set selectRows = Range(col & topCell.Row & ":" & col & bottomCell.Row)
nRows = WorksheetFunction.CountA(selectRows)
test = WorksheetFunction.SumProduct(WorksheetFunction.IsText(selectRows) / WorksheetFunction.CountIf(selectRows, selectRows))
I have a bug in the computation for test, but I don't get it. Some help very appreciated
Thanks a lot
BR
Martin
Your first problem is the WorksheetFunction.CountIf(selectRows, selectRows) part of your test calculation. When there are no duplicates, this will result in a division by zero error. This will occur when typed into a worksheet as well, so you will either need to change your logic, or test for this case first.
Your Type Mismatch problem, I believe, is caused by the WorksheetFunction.IsText(selectRows) segment. I have not been able to figure out what is causing it, but as i mentioned in my comments, I think the IsText() function may not take a range in VBA like it does when typed into a cell.
I would probably approach this problem in a different way. Here's an example I found elsewhere on SO Count unique values in Excel
This mostly has worksheet formulas, but there is 1 answer with VBA code that you probably could adapt.
Another option is to create a collection and count the number of elements
Sub CountUnique()
Dim Col As New Collection
Dim i As Integer
On Error Resume Next
For i = 3 To 10
Col.Add Sheet1.Cells(i, 1).Value, Sheet1.Cells(i, 1).Value
Next
MsgBox Col.Count
On Error GoTo 0
End Sub