Excel VBA - Add row & make active - excel

Good evening
Please see the attached image for an example of my data. The strings in column A are grouped together.
The below code is a WIP to achieve the following...
Find the last occurrence of each delivery location & add a new row after.
In the newly created row, in the columns named Header11-14, add a formula to total the values in the above rows
Do some formatting
So far it adds the new row after each delivery location but what I can't figure out is how to add the sum formula. I know how to add the string but I can't figure out how to reference the cells above...
The image above what i'm trying to achieve.
Sub insertRow_totals()
Dim changeRow, counter As Integer
counter = 2
While Cells(counter, 1) <> ""
If Cells(counter, 1) <> Cells(counter - 1, 1) Then
Rows(counter).Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
counter = counter + 2
End If
counter = counter + 1
Wend
Rows(2).EntireRow.Delete
End Sub

you need to count how many rows with the same name there are (or remember the row index of the first one), then something like this should work
Sub insertRow_totals()
Dim changeRow, counter As Integer
counter = 2
FirstRow = 2
While Cells(counter, 1) <> ""
If Cells(counter, 1) <> Cells(counter - 1, 1) Then
Rows(counter).Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
For i = 11 To 14
ActiveSheet.Cells(counter, i).Formula = "=SUM(" & Cells(FirstRow, i).Address & ":" & Cells(counter - 1, i).Address & ")"
Next i
counter = counter + 1
FirstRow = counter
End If
counter = counter + 1
Wend
Rows(2).EntireRow.Delete
End Sub

Related

Excel VBA compare columns

I am trying to compare two tables on the same excel sheet between rows. Following is what i am trying to achieve. I have worked something out, but it's not functionnal as it deletes rows...
A B C D E F
E1 40 12 4 4/16/2017 E4
E2 20 1 5 6/22/2016 E2
E1 10 0 4 6/30/2017 E1
E1 40 12 6 4/16/2017 E4
Should turn into :
A B C D E F
E1 40 12 4;6 4/16/2017 E4
E2 20 1 5 6/22/2016 E2
E1 10 0 4 6/30/2017 E1
TASK 1
If column A matches
If column B matches
If column C matches
If column F matches
Then
Concatenate rows on lines D and add a ";" between values
And delete rows that are concatenated.
I have achieved this with this code (just added the condition for F but it's not workind) , but it's not functional already without it, as it doesn't store values in a dictionnary probably and jumps rows, so it doesn't concatenate all of the values in the sheet and skips some too...
Sub TEMPLATE()
Dim lngRow As Long For lngRow = ActiveSheet.Cells(Rows.Count, "B").End(xlUp).Row To 2 Step -1
If StrComp(Range("B" & lngRow), Range("B" & lngRow - 1), vbTextCompare) = 0 And
If StrComp(Range("A" & lngRow), Range("A" & lngRow - 1), vbTextCompare) = 0 And
If StrComp(Range("C" & lngRow), Range("C" & lngRow - 1), vbTextCompare) = 0 And
If StrComp(Range("F" & lngRow), Range("F" & lngRow - 1), vbTextCompare) = 0
Then
If Range("D" & lngRow) <> "" Then
Range("D" & lngRow - 1) = Range("D" & lngRow - 1) & ";" & Range("D" & lngRow)
End If
Rows(lngRow).Delete
End If
Next
End Sub
TASK 2
Since this is an update file, I would like to compare every rows on the old file and make changes, and highloght them, if possible. Let's say, if my E1 line up there has been added a value on B, it would highlight B case and add the value.
I don't know how to do this one, I believe it should loop between the old sheet and the updated sheet where I run the previous macro.
Thanks guys for your help !
The code below should complete your TASK 1. It assumes everything is in the first sheet. It works with your example, but I haven't tested it much further so beware. However, I think it's clear enough so you can edit it if needed.
TASK 1:
Sub filter_data()
'Initialize iterator at row 1
i = 0
'Loop through data until no more rows
Do While Sheets(1).Range("A1").Offset(i, 0).Value2 <> ""
'Get values of row
A_val_1 = Sheets(1).Range("A1").Offset(i, 0).Value2
B_val_1 = Sheets(1).Range("A1").Offset(i, 1).Value2
C_val_1 = Sheets(1).Range("A1").Offset(i, 2).Value2
D_val_1 = Sheets(1).Range("A1").Offset(i, 3).Value2
F_val_1 = Sheets(1).Range("A1").Offset(i, 5).Value2
'Loop through data again to check if duplicates
j = i 'Initialize iterator at row i
Do While Sheets(1).Range("A1").Offset(j, 0).Value2 <> ""
If j <> i Then 'Skip selected row
'Get values of row
A_val_2 = Sheets(1).Range("A1").Offset(j, 0).Value2
B_val_2 = Sheets(1).Range("A1").Offset(j, 1).Value2
C_val_2 = Sheets(1).Range("A1").Offset(j, 2).Value2
D_val_2 = Sheets(1).Range("A1").Offset(j, 3).Value2
F_val_2 = Sheets(1).Range("A1").Offset(j, 5).Value2
'If conditions satisfied
If A_val_1 = A_val_2 And B_val_1 = B_val_2 And C_val_1 = C_val_2 And F_val_1 = F_val_2 Then
'Concatenate on D
Sheets(1).Range("A1").Offset(i, 3).Value2 = Sheets(1).Range("A1").Offset(i, 3).Value2 & ";" & D_val_2
'Delete duplicate row
Sheets(1).Rows(j + 1).Delete
'Decrement incrementor by 1 to make up for deleted row
j = j - 1
End If
End If
j = j + 1 'increment
Loop
i = i + 1 'increment
Loop
End Sub
Maybe (?) I'll get back to TASK 2 later, but that should be very straightforward - you just need to loop through all cells, compare an highlight.
EDIT: Task 2 below as far as I understood it. It only checks for difference in the new sheet, highlights differences from old sheet cell-wise and appends the old value to the LEFT of the new value (can be changed). Again, it works with your example.
TASK 2:
Sub compare_data()
'Initialize sheets to compare; only cells on new sheet will be highlighted
old_sheet_idx = 1 'index of old sheet
new_sheet_idx = 2 'index of updated sheet
'Get number of populated rows & column in new sheet
new_sheet_rows = Range(Sheets(new_sheet_idx).Range("A1"), Sheets(new_sheet_idx).Range("A1").End(xlDown)).Count
new_sheet_cols = Range(Sheets(new_sheet_idx).Range("A1"), Sheets(new_sheet_idx).Range("A1").End(xlToRight)).Count
'Clear all formats in new sheet
Sheets(new_sheet_idx).Cells.ClearFormats
'Loop through all rows of new sheet
For i = 1 To new_sheet_rows
'Loop through all cells of the row
For j = 1 To new_sheet_cols
'Get cell value
new_cell = Sheets(new_sheet_idx).Range("A" & i).Offset(0, j - 1).Value2
old_cell = Sheets(old_sheet_idx).Range("A" & i).Offset(0, j - 1).Value2
'Compare
If new_cell <> old_cell Then
Sheets(new_sheet_idx).Range("A" & i).Offset(0, j - 1).Interior.ColorIndex = 6 'highlight yellow
Sheets(new_sheet_idx).Range("A" & i).Offset(0, j - 1).Value2 = old_cell & ";" & new_cell 'concatenate old value;new value
End If
Next j
Next i
End Sub

Permutations in VBA

I'm trying to create a macro that outputs all possible permutations starting with a column of some numbers where each consecutive number can't be greater than the number above it.
So, would I would like to do is to provide excel with a column of 15 values in Sheet1 ranging from 1 to 9. The values should be in descending order so that a number on a row below can never exceed the one above.
What I am trying to do is to output new permutations of this list, one new sheet per new list.
The upper limit of the values in the list would be specified so the number of permutations would be everything between the starting list and the upper limit value.
There is a condition that I can not break and that is that the value of a row below another row, can't have a greater value than the one above. There's an image that explains a bit.
So far my code is not even half way there and I feel completely lost.
I'm not even sure how to go about thinking about this problem let alone coding it.
Any input would be greatly appreciated.
Sub
doSomeStuff()
Dim maxNotch, startNotch, Counter As Integer
Dim shit As Range
maxNotch = 3
startNotch = ThisWorkbook.Sheets("Sheet1").Cells(2, 2)
Counter = startNotch
sheetnumber = 2
For j = st
artNotch To maxNotch
Set ws = ThisWorkbook.Sheets.Add(After:= _
ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
ws.Name = "Sheet" & sheetnumber
ThisWorkbook.Sheets("Sheet" & sheetnumber).Cells(2, 2).Value = Counter
For i = 1 To 3
ThisWorkbook.Sheets("Sheet" & sheetnumber).Cells(i + 1, 1).Value = 2 + i
If ThisWorkbook.Sheets("Sheet" & sheetnumber).Cells(i + 1, 2).Value <> Counter Then
k = Counter - ThisWorkbook.Sheets("Sheet" & sheetnumber - 1).Cells(i + 1, 2).Value
Debug.Print k
End If
Next i
sheetnumber = sheetnumber + 1
Counter = Counter + 1
Next j
Application.DisplayAlerts = True
End Sub
Function pop()
(ByVal j As Integer, k As Integer)
For i = 1 To 3
ThisWorkbook.Sheets("Sheet" & j + 1).Cells(i + 1, 1).Value = 2 + i
ThisWorkbook.Sheets("Sheet" & j + 1).Cells(2, 2).Value = Counter
If ThisWorkbook.Sheets("Sheet" & j + 1).Cells(i + 1, 2).Value <> Cou
nter Then
ThisWorkbook.Sheets("Sheet" & j + 1).Cells(i + 1, 2).Value = ThisWorkbook.Sheets("Sheet" & j).Cells(i + 1, 2).Value
End If
Next i
End Function
Example from my comment, to account for the ordering:
dim pc as long, ws as worksheet
for each ws in worksheets
with ws
If ws.name <> "sourcedatasheet" then
.cells(2,2).resize(pc).value = "" 'export your list; pc = permutation count
.Range(.Cells(1,2),.Cells(pc+1,2)).Sort key1:=.Cells(1,2), order1:=xlDescending, Header:=xlYes 'used a header because row 1 is blank
end if
end with
next
Edit1:
Adding an if-statement to account for some specific sheet to not be included

VBA Looping to compare multiple values

I have created a nested for loop to compare 3 different cell values within 2 sheets. The loop works fine when the data is small, but when I run on 5,000 rows its too slow and crashes excel. Any idea of how to run this more efficiently.
Sub RowMatch()
Dim x As Integer
' Make sure we are in the right sheet
Worksheets("Q416").Activate
' Set numrows = number of rows of data.
NumRows = Range("C2", Range("C2").End(xlDown)).Rows.count
' find the reference range
Worksheets("Q415").Activate
NumRows2 = Range("C5", Range("C5").End(xlDown)).Rows.count
Worksheets("Q416").Activate
MsgBox ("Total # of Rows on this sheet = " & NumRows & " and " & NumRows2 & " in Ref Range")
Range("A1").Select
' Establish "For" loop to loop "numrows" number of times.
For x = 1 To NumRows
'MsgBox NumRows2
For y = 1 To NumRows2
'MsgBox (ActiveCell.Offset(x, 0).Value & " & " & Worksheets("Q415").Cells(y + 1, 1))
If ActiveCell.Offset(x, 0).Value = Worksheets("Q415").Cells(y + 1, 1).Value _
And ActiveCell.Offset(x, 2).Value = Worksheets("Q415").Cells(y + 1, 3).Value Then
If ActiveCell.Offset(x, 5).Value = Worksheets("Q415").Cells(y + 1, 6).Value Then
'If NumRows(i).Value = ActiveCell.Offset(1, 0).Value Then
ActiveCell.Offset(x, 10).Value = "Same"
Else
ActiveCell.Offset(x, 10).Value = ActiveCell.Offset(x, 5).Value - Worksheets("Q415").Cells(y + 1, 6).Value
End If
End If
Next y
Next x
End Sub
Reading and writing to cells is one of the slowest operations you can do in Excel VBA. Instead, you should place the values contained in the worksheets into arrays and work with them there, Here is an excellent reference: http://www.cpearson.com/excel/ArraysAndRanges.aspx. Use your NumRows variables and either a column letter or number to define the ranges that will consitute the arrays e.g:
myRange = Range("A1:C" & NumRows)
myArray = myRange.value
From the link to Chip Pearsons site:
Dim Arr() As Variant
Arr = Range("A1:B10")
Dim R As Long
Dim C As Long
For R = 1 To UBound(Arr, 1) ' First array dimension is rows.
For C = 1 To UBound(Arr, 2) ' Second array dimension is columns.
Debug.Print Arr(R, C)
Next C
Next R

Using a cell's number to insert that many rows (with that row's data)

I have data in excel that looks like this
{name} {price} {quantity}
joe // 4.99 // 1
lisa // 2.99 // 3
jose // 6.99 // 1
Would it be hard to make a macro that will take the quantity value ("lisa // 3.99 // 3") and add that many rows below it's current location. It would know which rows to copy, and how many rows to insert based on on the quantity column.
Thanks for reading, and feedback is helpful.
This will do what you want, it polls through from the bottom up, if it encounters a number in C and it is > 1 then it will insert the number of rows equal to column C number - 1 then copy the data from the host row.
This will give you 4 equal rows where there is a 4 in column C, I think that is what you were after yes? If you want to ADD the number of rows equal to column C (So a value of 4 would add 4 NEW rows making the total count for that entry become 5) then let me know, it will be simple enough to change this
Sub InsertRowsByQTY()
Dim X As Long
For X = Range("A" & Rows.Count).End(xlUp).Row To 1 Step -1
If IsNumeric(Range("C" & X).text) Then
If Range("C" & X).Value > 1 Then
Rows(X + 1).Resize(Range("C" & X).Value - 1, Columns.Count).Insert
Range("A" & X + 1).Resize(Range("C" & X).Value - 1, Cells(X, Columns.Count).End(xlToLeft).column).Value = Range("A" & X).Resize(1, Cells(X, Columns.Count).End(xlToLeft).column).Value
End If
End If
Next
End Sub
Another method :
Sub insert()
Dim lastrow As Integer, frow As Integer
lastrow = Range("C65536").End(xlUp).Row
frow = 0
For i = 2 To lastrow
If Cells(i, 3) > 1 Then
frow = frow + Cells(i, 3)
End If
Next i
For i = 2 To lastrow + frow
If Cells(i, 3) <> 1 Then
nr = Cells(i, 3)
Rows(i + 1 & ":" & i + nr).Select
Selection.insert Shift:=xlDown
Rows(i & ":" & i + nr).Select
Selection.FillDown
i = i + nr
End If
Next i
End Sub

Excel Macro Duplicate / Sort

This is the macro i am using, it looks at a field (AS) and then depending on the number in that column it will create the same amount of rows underneath. So for example if AS has '4' it will create 4 rows containing the number 4.
I need an amendment to this so that these rows will show 1-4, 2-4, 3-4, 4-4
Sub addlabels()
Dim r As Long
For r = Cells(Rows.Count, 1).End(xlUp).Row To 2 Step -1
If Cells(r, "AS") > 1 Then
Cells(r, 1).EntireRow.Copy
Cells(r + 1, 1).EntireRow.Resize(Cells(r, "AS").Value - 1).Insert shift:=xlDown
End If
Next r
End Sub
Here is an example image of how i need the column to display at the moment it just simply copies from the top field http://i.stack.imgur.com/p8bl8.png
May be you can try like this:
Considering the field("AS") is in cell a1 i've used the following code:
Sub addinglabels()
Dim i As Integer
cellvalue = ActiveSheet.Range("A1").Value
If (cellvalue > 1) Then
For i = 1 To cellvalue
Cells(i + 1, 1).Value = i & "--" & cellvalue
Next i
End If
End Sub

Resources