Why does this loop not carry out all steps each time? - excel

I’ve been writing a macro to format spreadsheets based on client preference. The part of the macro I’m having trouble with is getting percentage columns to format as percentages with one place after the decimal. In the code below, I determine where my % column will be (they’re headed with ‘Cov’ on the file I’m working in), and once that column is identified, the macro loops thru each row in the column and enters the % formula until the last row is reached.
Everything works mostly as intended, except the last two (2) columns that get the % formula do NOT update to show one place after the decimal. Can anyone provide insight to why the last two columns don't update the same as the others that are part of the loop?
Thank you!
For C = 24 To LastColumn + 2
If .Cells(12, C) = "Cov" Then
For i = 13 To LastRow
Set formatCell = .Range(.Cells(i, C), .Cells(i, C))
formatCell.Value = "=IFERROR(" & .Cells(i, C - 1).Address & "/" & .Cells(i, 14).Address & "*100,0)"
formatCell.NumberFormat = "0.0"
Next i
End If
Next C

Related

How to solve type mismatch (Run Error 13) for Date in VBA?

I am writing a VBA code in my excel. I have employees date of birth on Row F. Now, using VBA, I want phrase called "Happy Birthday" on column G for those employees who have birthdays. My table starts from row 6 to row 50. I wrote the following code but it always gives error in Month(Range("f" & y)). The month function gives me error. If, for example, I only write Range("f" & y), it will work fine. This means the Date of birth on column F isn't being recognized as DATE in my VBA (they are in date format in excel). There is a mismatch for sure. Can someone please help me how to fix this issue (using for next function as shown below)?>
Sheets("Employees").Select
For y = 6 To 50
If Month(VBA.Date) = Month(Range("f" & y)) Then
Range("g" & y).Value = "HBD"
Else
Range("g" & y).Value = "No hbd"
End If
Next y
Note: A). I am looking at the month of date of birth only for wishing happy birthday and I am not looking at day. B). I want message called HBD or NO HBD to be posted on column G for each employee based on their DOB given on Column F .
With a formula I think you should be able to do it with =IF(MONTH(TODAY())=MONTH(F6),"HBD","No HBD").
For a VBA solution use:
Sub Test()
Dim y As Long
With ThisWorkbook.Worksheets("Employees")
For y = 6 To .Cells(.Rows.Count, 6).End(xlUp).Row
If Month(Date) = Month(.Cells(y, 6)) Then
.Cells(y, 7) = "HBD"
Else
.Cells(y, 7) = "No HBD"
End If
Next y
End With
End Sub
NB: Cells(Row, Column) is used in place of Range - easier for referencing a single cell using row/column numbers.

Looping Through Column and Saving Resultant into new column

I am having trouble trying to figure out how to save a result of a for loop as it goes through each row.
For example if you have A1:A45 filled with values and you want to add 6 to each cell in that range and output the resultant for each operation into column B.
I am just missing the portion that gets the for loop to output into a new column for every operation performed. I think from there I can troubleshoot and google tutorials.
This is a snippet of a macro I am making. After my concatenation operation I would like to save the new string to a new column and as it goes through the loop, the resultant string would save sequentially.
Select Case numCav
Case Is = 4
For a = 2 To lastUserDim1
For cavNum = 1 To 4
newDimName = .Cells(a, 1).Value2 & "_Cav" & cavNum
.Cells(a, 8) = newDimName
Next cavNum
Next a
If you are just looking to output the newDimName into the next available cell in column 8, then you can use .End(xlUp):
.Cells(.Rows.Count, 8).End(xlUp).Offset(1).Value = newDimName
All this is doing is starting from the very bottom of column 8 (Rows.Count is the number of the last row), then going up (equivalent of Ctrl and ↑), then Offsetting one to the next row.

Convert part of Formula from Relative to Absolute Reference

Originally I wanted to change parts of a formula in every 82th row where the formula looks like
=SUMIFS($BJ:$BJ;$BO:$BO;$BI7382;$A:$A;"<="&$A7382;A:A;">"&A7383)
So I wanted to change each formula for a thousand of rows from (...;$BI7382;...;"<="&$A7382;...) to:
(...;$BI$7382;...;"<="&$A$7382;...) where $7382 is always one row before the row that includes the formula above.
So the next row with this formula would be $7464 where my code should change from (...;$BI7463;...;"<="&$A7463;...) to:
(...;$BI$7463;...;"<="&$A$7463;...) and so on.
I had success with your code
For i = 7383 To Cells(Rows.Count, 1).End(xlUp).Row Step 82
Cells(i, 1).Formula = Replace(Cells(i, 1).Formula, "$BI" & i - 1, "$BI$" & i - 1)
Cells(i, 1).Formula = Replace(Cells(i, 1).Formula, "$A" & i - 1, "$A$" & i - 1)
But: There is a single column which has cells with
=SUMIFS($BJ:$BJ;$BO:$BO;$BI7382;$A:$A;<="&$A7382;A:A;">"&$A7383)
where the last value has changed from
">"&A7383to">"&$A7383
such that the last two values both have absolute column references
Because the code finds two values with $A... the replace function does not work properly
(Cells look like =SUMIFS($BJ:$BJ;$BO:$BO;$BI7382;$A:$A;"<="&$A7382;A:A;">"& after the code is executed
The problem is that the string "SUMIFS($BI" & cl.Row - 1 does not exist in your formula, so nothing gets replaced. Try the following line, it should work.
cl.Formula = Replace(cl.Formula, "$BI" & cl.Row - 1, "$BI$" & cl.Row - 1)
Now, it is better to declare the variable i as an Integer since it is used as a row index, and row indexes are integers. That way we avoid inaccuracy of Double (i.e. floating-point) arithmetic.
Dim i As Integer
In the For loop, i starts at 7383 and is incremented by steps of 81. This is good. However, i is not used anywhere in the replace statement. But the For Each loops through all rows of column O. The For Each is not needed. You can access cells in column O with Cells(i, 15). So the For loop becomes:
For i = 7383 To Cells(Rows.Count, 1).End(xlUp).Row Step 81
Cells(i, 15).Formula = Replace(Cells(i, 15).Formula, "$BI" & i - 1, "$BI$" & i - 1)
Next i
The upper bound value of i in the For loop is determined by the contents of column A. If column A has fewer rows than column O, then some replacements may be missed.

Comparing two data tables on different tabs in Excel using VBA

I am relatively new to Macros and VBA in Excel, so I need some guidance on how to solve my current issue.
The end goal of my project is to have a macro compare two sets of data organized into rows and columns (We'll say table A is the source data, and table B is based off of user input). Each row in table B should correspond to a row in table A, but they could be out of order, or there could be incorrect entries in table B.
My thought is that for the first row in each table, the macro would compare each cell left to right:
If Sheets("sheet1").Cells(2, 1) = Sheets("sheet2").Cells(2, 1) Then
If Sheets("sheet1").Cells(2, 2) = Seets("sheet2").Cells(2, 2)
Ect, ect.
My problem comes in when the Cell in table B does not match Table A.
First, I would want it to check B row 1 against the next row in A, and keep going throughout table A until it finds a "complete match" with all five columns of the row matching.
I've been trying to do this with Else if and For/Next staements
For row= 2 to 10
'if statements go here
Else If Sheets("sheet1").Cells(2, 1) <> Sheets("sheet2").Cells(2, 1)
Next row
I may be completely misunderstanding the syntax here, but I have yet to produce a situation where if the criteria is not met, it goes to the next row.
If no complete match is found, the last cell in table B row 1 that couldn't be matched should be highlighted.
Then regardless of whether a match was found or not, we would move to table B row 2, and start the whole process over.
So, I have the logic worked out (I think), where the comparison ifs would be inside a loop (or something) that would cycle through table A row by row. Then that whole process would be in another loop (or something) that would cycle through Table B.
At the end of the process, there would either be no highlighted cells showing that all entered data is correct, or cells would be highlighted showing data that do no match.
I am fairly certain that the cycling through table B is not the issue. Rather, I'm having difficulty getting the Macro to move to the next table A row if something doesn't match.
Please let me know if I need to elaborate on anything.
Thanks!
You could try:
Option Explicit
Sub test()
Dim Lastrow1 As Long, Lastrow2 As Long, i As Long, j As Long
Dim Str1 As String, Str2 As String
'Find the last row of sheet 1
Lastrow1 = Sheet1.Cells(Sheet1.Rows.Count, "A").End(xlUp).Row
'Find the last row of sheet 2
Lastrow2 = Sheet2.Cells(Sheet2.Rows.Count, "A").End(xlUp).Row
For i = 2 To Lastrow1
'Let us assume that table has 3 columns. Merge 3 columns' values and create a string for each line
Str1 = Sheet1.Cells(i, 1).Value & "_" & Sheet1.Cells(i, 2).Value & "_" & Sheet1.Cells(i, 3).Value
For j = 2 To Lastrow2
'Let us assume that table has 3 columns. Merge 3 columns' values and create a string for each line
Str2 = Sheet2.Cells(j, 1).Value & "_" & Sheet2.Cells(j, 2).Value & "_" & Sheet2.Cells(j, 3).Value
'If both strings match a message box will appear
If Str1 = Str2 Then
MsgBox "Line " & i & " in table A match with line " & j & " in table B!"
Exit For
End If
Next j
Next i
End Sub
Sheet 1 structure:
Sheet 2 structure:

Create new Excel rows based on column data

Good afternoon all,
I have an issue where I have users who have multiple bank account details. I need to try and create a new row for each employee who has more than one bank account, with the second bank account being allocated a new row.
Employee Number User ID BSB Account number
10000591 WOODSP0 306089,116879 343509,041145273
10000592 THOMSOS0 037125 317166
I need it to look something like this:
Employee Number User ID BSB Account number
10000591 WOODSP0 306089 343509
10000591 WOODSP0 116879 041145273
10000592 THOMSOS0 037125 317166
Any thoughts? Your input is greatly appreciated!
Screenshots are here to demonstrate:
Right click on the tab and choose "View Code"
Paste this code in:
Sub SplitOnAccount()
Dim X As Long, Y As Long, EmpNo As String, UserID As String, BSB As Variant, AccNo As Variant
Range("F1:I1") = Application.Transpose(Application.Transpose(Array(Range("A1:D1"))))
For X = 2 To Range("A" & Rows.Count).End(xlUp).Row
EmpNo = Range("A" & X).Text
UserID = Range("B" & X).Text
BSB = Split(Range("C" & X).Text, ",")
AccNo = Split(Range("D" & X).Text, ",")
For Y = LBound(AccNo) To UBound(AccNo)
Range("F" & Range("F" & Rows.Count).End(xlUp).Row).Offset(1, 0).Formula = EmpNo
Range("G" & Range("G" & Rows.Count).End(xlUp).Row).Offset(1, 0).Formula = UserID
Range("H" & Range("H" & Rows.Count).End(xlUp).Row).Offset(1, 0).Formula = BSB(Y)
Range("I" & Range("I" & Rows.Count).End(xlUp).Row).Offset(1, 0).Formula = AccNo(Y)
Next
Next
End Sub
Close the window to go back to excel
Press ALT-F8
Choose SplitOnAccount and click run.
Note, this is going to populate the split data to rows F to I, make sure there is nothing in there. If there is post back and we can change it.
Also format columns F - I as text before you run it or Excel will strip leading zeros off as it will interpret it as a number.
Here is another sub that appears to perform what you are looking for.
Sub stack_accounts()
Dim rw As Long, b As Long
Dim vVALs As Variant, vBSBs As Variant, vACTs As Variant
With ActiveSheet '<-define this worksheet properly!
For rw = .Cells(Rows.Count, 1).End(xlUp).Row To 2 Step -1
vVALs = .Cells(rw, 1).Resize(1, 4).Value
vBSBs = Split(vVALs(1, 3), Chr(44))
vACTs = Split(vVALs(1, 4), Chr(44))
If UBound(vBSBs) = UBound(vBSBs) Then
For b = UBound(vBSBs) To LBound(vBSBs) Step -1
If b > LBound(vBSBs) Then _
.Rows(rw + 1).Insert
.Cells(rw - (b > LBound(vBSBs)), 1).Resize(1, 4) = vVALs
.Cells(rw - (b > LBound(vBSBs)), 3).Resize(1, 2).NumberFormat = "#"
.Cells(rw - (b > LBound(vBSBs)), 3) = CStr(vBSBs(b))
.Cells(rw - (b > LBound(vBSBs)), 4) = CStr(vACTs(b))
Next b
End If
Next rw
End With
End Sub
I was originally only going to process the rows that had comma delimited values in columns C and D but I thought that processing all of them would allow the macro to set the Text number format and get rid of the Number as text error warnings and keep the leading zero in 041145273.
        
You Can definitely use Power Query to transform the data to generate new rows using split column option.
Check this article it explains the process in detail.
Load Data in Power Query section of excel.
Create an Index (Not required step)
Use Split column function with advance options and split them into new rows.
Save this result into new table for your use.
I did it myself and it worked like a charm.
A formula solution:
Delimiter: Can be a real delimiter or an absolute reference to a cell containing only the delimiter.
HelperCol: I have to use a helper column to make it work. You need to give the column letter.
StartCol: The column letter of the first column containing data.
SplitCol: The column letter of the column to be splitted.
Formula1: Used to generate the formula for the first column not to be splitted. You can fill this formula down and then fill to right.
Formula2: Used to generate the formula for the column to be splitted(only support split one column).
Formula3: Used to generate the formula for the Helper column.
(If the title of the column to be splitted contains the delimiter, you must change the first value of the helper column to 1 manually.)
Formula1:=SUBSTITUTE(SUBSTITUTE("=LOOKUP(ROW(1:1),$J:$J,A:A)&""""","$J:$J","$"&B2&":$"&B2),"A:A",B3&":"&B3)
Formula2:=SUBSTITUTE(SUBSTITUTE(SUBSTITUTE("=MID($M$1&LOOKUP(ROW(A1),$J:$J,F:F)&$M$1,FIND(""艹"",SUBSTITUTE($M$1&LOOKUP(ROW(A1),$J:$J,F:F)&$M$1,$M$1,"&"""艹"",ROW(A2)-LOOKUP(ROW(A1),$J:$J)))+1,FIND(""艹"",SUBSTITUTE($M$1&LOOKUP(ROW(A1),$J:$J,F:F)&$M$1,$M$1,""艹"",ROW(A2)-LOOKUP(ROW(A1),$J:$J)+1))-FIND(""艹"",SUBSTITUTE($M$1&LOOKUP(ROW(A1),$J:$J,F:F)&$M$1,$M$1,""艹"",ROW(A2)-LOOKUP(ROW(A1),$J:$J)))-1)&""""","$M$1",IF(ISERROR(INDIRECT(B1)),""""&B1&"""",B1)),"$J:$J","$"&B2&":$"&B2),"F:F",B4&":"&B4)
Formula3:=SUBSTITUTE(SUBSTITUTE(SUBSTITUTE("=SUM(E1,LEN(B1)-LEN(SUBSTITUTE(B1,$H$1,"""")))+1","B1",B4&1),"$H$1",IF(ISERROR(INDIRECT(B1)),""""&B1&"""",B1)),"E1",B2&1)
Helper must filled one row more than the data.
How to use:
Copy the formula generated by the above three formula.
Use Paste Special only paste the value.
Make the formula into effect.
Fill the formula.
Bug:
Numbers will be converted to Text. Of course you can remove the &"" at the end of the formula, but blank cells will be filled with 0.
ps. This method may by very hard to comprehend. But once you master it, it can be very useful to solve relative problems.

Resources