Compare and insert row (VBA) - excel

I'm trying my excel file to:
Compare columns G and H
- If they have the same text -> go to the next row to continue the comparison
- If they don't have the same text -> Insert a row below G and then continue the comparison.
The result would be this:
Before running the macro (first column is G, second column is H):
After running the macro:
Can you help me with this, please?
Thanks a lot.

Something like this
Sub CompArray()
Dim G
Dim H
Dim X
Dim lngCnt As Long
Dim lngMark As Long
G = Range([g1], Cells(Rows.Count, "G").End(xlUp))
H = Range([H1], Cells(Rows.Count, "H").End(xlUp))
X = H
For lngCnt = 1 To UBound(X, 1)
If G(lngCnt - lngMark, 1) = H(lngCnt, 1) Then
X(lngCnt, 1) = G(lngCnt - lngMark, 1)
Else
lngMark = lngMark + 1
X(lngCnt, 1) = vbNullString
End If
Next
[g1].Resize(UBound(X), 1) = X
End Sub

You can select the range you want to look at and then loop through the rows.
Compare the cells, if they are not the same, select the right cell.
Then insert in new cell and move everything to 1 cell down
This code s a bit slow, because it selects the whole column.
You can change compare statement to make a different compare
Dim rngCompare As Range
Dim rowCount As Long
Dim iCount As Long
Set rngCompare = ActiveSheet.Columns("D:E")
rowCount = rngCompare.Rows.Count
For iCount = 1 To rowCount
If StrComp(rngCompare.Cells(iCount, 1), rngCompare.Cells(iCount, 2), vbTextCompare) <> 0 Then
rngCompare.Cells(iCount, 1).Select
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
End If
Next iCount

Related

Excel VBA - add rows in dependence of a value in a cell

I have a table with information in column A and an appropriate value in column B. I want to write a macro that inserts a new row for each "Person" in dependence of the value in column B and copies the original information into that row, which for example means that in the end there are 5 rows with "Person A", 2 rows for "Person B" etc.
original table:
result:
My first approach looks like that. It doesn't work.
Dim i, j, k As Integer
For i = Range("A" & Range("A:A").Rows.Count).End(xlUp).Row To 1 Step -1
For j = 1 To Range("B" & i)
Rows(i).Select
Selection.Insert Shift:=xlDown
k = k + j
Range(Cells(k, 1), Cells(k, 2)).Copy Destination:=Range("A" & i)
Next j
Next i
This would work for you, changing the number of inserts based on value in column B:
Option Explicit
Sub test()
With Sheets(1)
Dim lastRow As Long: lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
Dim i As Long
For i = lastRow To 1 Step -1
If IsNumeric(.Cells(i, 2).Value) = True Then
Dim numberOfInserts As Long
numberOfInserts = .Cells(i, 2).Value - 1
If numberOfInserts > 0 Then
Dim insertCount As Long
For insertCount = 1 To numberOfInserts
.Rows(i).Copy
.Rows(i).Insert
Next insertCount
End If
End If
Next i
End With
End Sub
First we check that you're dealing with numbers. Second you have a single line already, so number -1, then that this number is >0. Lastly, you insert via a loop which does the counting for you.
Test data:
Output after running:
Your index calculation is messed up. Use the debugger, step thru the code (F8) and notice what happens:
a) Your Select/Insert-construct creates a new row above the row you want to copy, not below.
b) Your calculation of index k fails: You are not initializing k, so it starts with value 0. Than you add j (1..3) to k, resulting in values 1, 3, 6, and copy data from that line.
I would suggest you take a different approach: Copy the original data into an array and then loop over that array. This avoids multiple Select, Copy and Insert statements (that are slow) and allow to copy the data from top to bottom.
Sub copy()
Dim rowCount As Long
Dim data As Variant
With ActiveSheet ' Replace with the sheet you want to work with
' Copy the current table into array
rowCount = .Cells(.Rows.Count, 1).End(xlUp).row
data = .Range(.Cells(1, 1), .Cells(rowCount, 2))
Dim oldRow As Long, newRow As Long
newRow = 1
' Loop over old data
For oldRow = 1 To rowCount
Dim repeatCount As Long
repeatCount = Val(data(oldRow, 2)) ' We want to have so many occurrences of the row
if repeatCount <= 0 Then repeatCount=1
Dim col As Long
' Create "repeatCount" rows of data (copy column by column)
For col = 1 To 2
.Cells(newRow, col).Resize(repeatCount, 1) = data(oldRow, col)
Next col
newRow = newRow + repeatCount
Next
End With
End Sub

wrap text of a sheet with merged and not merged cells

I have a sheet with some cells are merged in rows, and some are not. I want to wrap all the cells and if rows contains merged cells, set the rows height to max of all cells height
In the excel file, you can find the sheet I am working with, what I want to have, the excel macro I wrote, what I get with that macro. I also put them here.
This is what I have: (column D is a hidden column)
This is what I want to have: (for the rest of the sheet see attached excel file)
I wrote an excel VBA macro to do the job, but there is no luck.
Sub MergeCells2()
Application.DisplayAlerts = False
Dim allRange As Range
Dim xCell As Range
On Error Resume Next
Dim i_row As Integer
Dim nRowsToMerge As Integer
Dim rangeToMerge As Range
Worksheets("What I have").Activate
LastCol = ActiveSheet.Range("a1").End(xlToRight).Column
LastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, LastCol).End(xlUp).Row
Set allRange = Application.Range("a1", ActiveSheet.Cells(LastRow, LastCol))
allRange.WrapText = True
If allRange Is Nothing Then Exit Sub
nRowsToMerge = 1
Set heightToSet = Range("A2").RowHeight
For i_row = 2 To LastRow
Set i_rowRange = allRange.Rows(i_row - 1)
If (allRange.Cells(i_row, 1) = "") Then
nRowsToMerge = nRowsToMerge + 1
ElseIf nRowsToMerge = 1 Then
heightToSet = i_rowRange.RowHeight
Else
Set rangeToMerge = ActiveSheet.Range(ActiveSheet.Cells(i_row - nRowsToMerge, 1), ActiveSheet.Cells(i_row - 1, LastCol))
For Each xCell In rangeToMerge
cellrow = xCell.Row
If (rangeToMerge.Cells(cellrow, 1) = "") Then
If xCell.Value = "" Then
Range(xCell, xCell.Offset(-1, 0)).Merge
End If
End If
Next
rangeToMerge.RowHeight = heightToSet
heightToSet = i_rowRange.RowHeight
nRowsToMerge = 1
End If
Next i_row
End Sub
This is what I get:
I don't know what is wrong with it and I have to say that I don't know much about VBA programming.
I hope I was clear with my question.
Please help, I am working on this for days now :(
Cheers,
Eda
The idea:
Start by wrapping all cells, and using AutoFit for all rows. This way Excel will automatically set the row height properly.
Loop through the rows merging the cells and dividing the height of the row with the wrapped text over the rows to be merged.
This is how:
Sub NewMerger()
Dim r As Long, rMax As Long, re As Long, cMax As Long, c As Long, n As Long, h As Single, mr As Long
Application.DisplayAlerts = False
'Create a copy of the input
Sheets("What I have").Copy After:=Sheets(Sheets.Count)
On Error Resume Next
Sheets("New Result").Delete
ActiveSheet.Name = "New Result"
'merge and use autofit to get the ideal row height
Cells().WrapText = True
Rows.AutoFit
'get max row and column
cMax = Cells(1, 1).End(xlToRight).Column
rMax = Cells(Rows.Count, 1).End(xlUp).Row
'loop through rows, bottom to top
For r = rMax To 2 Step -1
If Cells(r, 1).Value = "" Then
If re = 0 Then re = r 'If we don't have an end row, we do now!
ElseIf re > 0 Then 'If re has an end row and the current row is not empty (AKA start row)
h = Rows(r).RowHeight 'Get the row height of the start row
n = re - r + 1 'calculate the number of rows
If n > 0 Then Rows(r & ":" & re).RowHeight = h / n 'devide the row hight over all rows
For c = 1 To cMax 'And merge
For mr = re To r Step -1 'Merge only empty cells
If Cells(mr, c).Value = "" Then
Range(Cells(mr, c), Cells(mr - 1, c)).MergeCells = True
End If
Next
Next
re = 0 'We don't have an end row now
End If
Next
Application.DisplayAlerts = True
End Sub

Make every set of eight rows move into columns in Excel

I would like to make every set of eight rows move into columns in Excel for example here is a set with every four rows broken into columns:
From this:
To this:
I've tried this code in VBA which I've seen in a previous question found on https://superuser.com/questions/583595/move-every-7-columns-into-new-row-in-excel
Dim i As Integer, j As Integer, cl As Range
Dim myarray(100, 6) As Integer 'I don't know what your data is. Mine is integer data
'Change 100 to however many rows you have in your original data, divided by seven, round up
'remember arrays start at zero, so 6 really is 7
If MsgBox("Is your entire data selected?", vbYesNo, "Data selected?") <> vbYes Then
MsgBox ("First select all your data")
End If
'Read data into array
For Each cl In Selection.Cells
Debug.Print cl.Value
myarray(i, j) = cl.Value
If j = 6 Then
i = i + 1
j = 0
Else
j = j + 1
End If
Next
'Now paste the array for your data into a new worksheet
Worksheets.Add
Range(Cells(1, 1), Cells(101, 7)) = myarray
End Sub
However, it only seems to work with integers and not data that has both numbers and letters if I am understanding correctly.
I get an error:
Run-time error '13':
Type mismatch
This should do it
Sub movedata()
Dim rowcounter, colcounter, rowcounter2 As Long
colcounter = 3
rowcounter2 = 1
For rowcounter = 1 To Cells(Cells.Rows.Count, 1).End(xlUp).Row
If Cells(rowcounter, 1).Value2 <> "" Then
Cells(rowcounter2, colcounter).Value2 = Cells(rowcounter, 1).Value2
colcounter = colcounter + 1
Else
rowcounter2 = rowcounter2 + 1
colcounter = 3
End If
Next rowcounter
End Sub
So you basically want to transpose the used range of a given sheet? This code may
Option Explicit
Sub transpose()
Dim a As Integer, x As Integer
a = 1 + Cells(1, 1).End(xlToRight).Column
ActiveSheet.UsedRange.Copy
Cells(1, a).Select
Selection.PasteSpecial Paste:=xlPasteAll, transpose:=True
Cells(1, 1).Select
For x = 1 To (a - 1)
Columns(1).Delete
Next x
End Sub
It works as follows:
- find the last used column and define "a" as this columnnumber + 1
- Copy the used range (where your data is)
- transpose into cells(1,a)
- select cells(1,1)
- delete this column (a-1) times
Is this what you are looking for?

Need help copy/pasting in Excel VBA from one workbook to another

I need to find out how to write some basic code that will take each cell's value (which will be an ID number) from a selected range, then match it to a cell in a master workbook, copy said cell's entire row, then insert it into the original document in place of the ID number. Here's the kicker: certain ID numbers may match with several items, and all items that have that number must be inserted back into the document. Here's an example:
Master Document Workbook
A B C D A B C D
1 a ab ac 2
2 b bc bd 3
2 b be bf
3 c cd de
I would select the cells containing 2 and 3 in the Workbook, which after running the code would give me this:
Workbook
A B C D
2 b bc bd
2 b be bf
3 c cd de
Here's what I have going on so far but it's a total mess. The only thing it's managed to successfully do is store the selected range in the Workbook I want to paste to. It won't compile past that because I don't understand much of the syntax in VBA:
Sub NewTest()
Dim rng As Range
Dim FirstRow As Range
Dim CurrentCol As String
Dim FirstRowVal As Integer
Dim CurrentColVal As Variant
Dim rngOffset As Range
CurrentCol = "Blah"
Set FirstRow = Application.InputBox("Select the row containing your first raw material", Type:=8)
FirstRowVal = FirstRow.Row
Set rng = (Application.InputBox("Select the cells containing your IC numbers", "Obtain Materials", Type:=8))
Set rngOffset = rng.Offset(0, FirstRowVal)
CurrentColVal = rng.Column
Call CopyPaste
End Sub
Sub CopyPaste()
Dim Blah As Range
Set x = Workbooks.Open("Workbook Path")
Workbooks.Open("Workbook Path").Activate
Set y = Workbooks.Open("Master Path")
Workbooks.Open("Master Path").Activate
With x
For Each Cell In rng
x.Find(rng.Cell.Value).Select
If Selection.Offset(0, -1) = Selection Then
Selection.EntireRow.Copy
Selection = Selection.Offset(0, -1)
Else
Selection.EntireRow.Copy
Blah = Selection
End If
Workbooks.Open("Workbook Path").Activate
Sheets("Formula Sheet").Select
Blah.Insert (rng.Cell)
End
Sheets("sheetname").Cells.Select
Range("A1").PasteSpecial
'Sheets("sheetname").PasteSpecial
.Close
End With
With x
.Close
End With
End Sub
Would very much appreciate anyone who could help point me in the right direction. Thanks.
I'll bite, you can use the output array to populate any range on any worksheet.
Sub FindAndMatch()
Dim arrMatchFrom() As Variant, arrMatchTo() As Variant, arrOutput() As Variant
Dim i As Integer, j As Integer, counter As Integer
counter = 0
arrMatchFrom = Range("A2:D6")
arrMatchTo = Range("G2:G3")
For i = LBound(arrMatchTo, 1) To UBound(arrMatchTo, 1)
For j = LBound(arrMatchFrom, 1) To UBound(arrMatchFrom, 1)
If arrMatchTo(i, 1) = arrMatchFrom(j, 1) Then
counter = counter + 1
ReDim Preserve arrOutput(4, counter)
arrOutput(1, counter) = arrMatchTo(i, 1)
arrOutput(2, counter) = arrMatchFrom(j, 2)
arrOutput(3, counter) = arrMatchFrom(j, 3)
arrOutput(4, counter) = arrMatchFrom(j, 4)
End If
Next
Next
For i = 1 To counter
For j = 1 To 4
Debug.Print arrOutput(j, i)
Cells(9 + i, j) = arrOutput(j, i)
Next
Next
End Sub

Remove duplicates from column A based on existing values in column B using VBA

I need to input data in column A and column B and get the data that's in column A but not in column B written to column C.
Examples of what I need:
A slightly different and faster approach without looping through cells on the sheet would be this...
Private Sub CommandButton1_Click()
Dim x, y(), dict
Dim i As Long, j As Long
x = Range("A1").CurrentRegion
Set dict = CreateObject("Scripting.Dictionary")
Columns("C").ClearContents
For i = 1 To UBound(x, 1)
dict.Item(x(i, 2)) = ""
Next i
j = 1
For i = 1 To UBound(x, 1)
If Not dict.exists(x(i, 1)) Then
ReDim Preserve y(1 To j)
y(j) = x(i, 1)
j = j + 1
End If
Next i
Range("C1").Resize(UBound(y), 1) = Application.Transpose(y)
End Sub
Place this in the code file behind your sheet and change CommandButton1 to the name of your button.
Option Explicit
Private Sub CommandButton1_Click()
Dim r As Range, matched_ As Variant, counter_ As Long
'Loop in each cell in Column A
For Each r In Range("A1:A" & Cells(Rows.Count, 1).End(xlUp).Row)
If Not IsEmpty(r) Then
'Loop for a matching value in Column B
matched_ = Application.Match(r.Value, Columns(2), 0)
'If match not found, write the value in Column C
If IsError(matched_) Then
counter_ = counter_ + 1
Range("C" & counter_) = r.Value
End If
End If
Next r
End Sub

Resources