Insert rows after every new reference shows up in a column - excel

I have data in a column and I am trying to run a macro so that a new row (a preset line) is inserted every time a new value is found.
Here is an example of how the data looks currently:
1 C 100
1 D 100
1 E 100
1 F 100
1 G 100
2 C 200
2 D 200
2 E 200
I want the macro to look in the first column and if there is a new value then insert a row (paste a predefined line)
This is the outcome:
1 C 100
1 D 100
1 E 100
1 F 100
1 G 100
Predefined line copied
2 C 200
2 D 200
2 E 200
Predefined line copied
My current code looks like this. It is not working:
Sub InsertCreditorLine()
'based on value in column AB, works out where new expense starts and inserts the creditor line formula row
Dim Col As Variant
Dim BlankRows As Long
Dim LastRow As Long
Dim PrintArea1 As Variant
Dim R As Long
Dim StartRow As Long
' works out last row to work up from
Col = "AB"
StartRow = 6
BlankRows = 1
LastRow = Cells(Rows.Count, Col).End(xlUp).Row
Application.ScreenUpdating = False
With ActiveSheet
For R = LastRow To StartRow + 1 Step -1
'Looks to value in column AB to see where new expense starts
If .Cells(R, Col) = "Y" Then
'paste in line
Rows("1:13").Select
Selection.EntireRow.Hidden = False
.Cells(7, 7).EntireRow.Copy
.Cells(R, Col).EntireRow.Insert Shift:=xlDown
End If
Next R
End With
Application.CutCopyMode = False

How about this?
Sub InsertCreditorLine()
Dim startRow As Long, lastRow As Long, presetRow As Range, rw As Long
startRow = 6
lastRow = Range("AB" & Rows.Count).End(xlUp).Row
Set presetRow = Range("7:7")
For rw = lastRow To startRow + 1 Step -1
If Range("AB" & rw) <> Range("AB" & rw).Offset(-1, 0) Then
presetRow.Copy
Range("AB" & rw).Insert Shift:=xlDown
End If
Next rw
End Sub

Related

return the value if its in within the range?

n this project i have to check column's A value between Column B and Column C. If columnA's values>= Columns B value or Columns A value<= Columns C value then i need to copy column d and e values and need to put into sheet1 column G and H. Column A is in sheet1 and Column B, C, D and E in sheet2.
A B C D E
1 1 9 Dog Naruto
11 10 19 Cat one piece
21 20 30 Duck lo
1
31
12
and so on
I want the outcome like this
A G H
1 Dog Naruto
11 cat One piece
21 duck o
1 Dog Naruto
31
12 cat One piece
and so on
This is the code I got with the help of someone but its limited. I want it to return value no matter how many rows A column has.
Dim i As Long
Dim lRow As Long
Dim colA As Double, colB As Double, colC As Double
lRow = Sheets("Sheet1").Range("A" &
Sheets("Sheet1").Rows.Count).End(xlUp).Row
For i = 2 To lRow
colA = Sheets("Sheet1").Range("A" & i).Value
colB = Sheets("Sheet2").Range("B" & i).Value
colC = Sheets("Sheet2").Range("C" & i).Value
If colA >= colB Or colA <= colC Then
Sheets("Sheet1").Range("G" & i).Value = Sheets("Sheet2").Range("D" &
i).Value
Sheets("Sheet1").Range("H" & i).Value = Sheets("Sheet2").Range("E" &
i).Value
End If
Next i
If column B in Sheet2 is in a ascending order …
… you can easily do that with a formula. In B2 add the following formula and pull it down and right.
=INDEX(Sheet2!D:D,MATCH($A:$A,Sheet2!$B:$B,1))
And you will get this output in Sheet1:
The same approach would be possible with VBA using Application.WorksheetFunction but I recommend to use the formula.
VBA Solution
Option Explicit
Public Sub FindAndFillData()
Dim wsDest As Worksheet
Set wsDest = ThisWorkbook.Worksheets("Sheet1")
Dim wsLookup As Worksheet
Set wsLookup = ThisWorkbook.Worksheets("Sheet2")
Dim LastRow As Long
LastRow = wsDest.Cells(wsDest.Rows.Count, "A").End(xlUp).Row
Dim MatchedRow As Double
Dim iRow As Long
For iRow = 2 To LastRow
MatchedRow = 0 'initialize!
On Error Resume Next
MatchedRow = Application.WorksheetFunction.Match(wsDest.Cells(iRow, "A").Value, wsLookup.Columns("B"), 1)
On Error GoTo 0
If MatchedRow <> 0 Then
If wsDest.Cells(iRow, "A").Value <= wsLookup.Cells(MatchedRow, "C").Value Then
wsDest.Cells(iRow, "B").Value = wsLookup.Cells(MatchedRow, "D").Value
wsDest.Cells(iRow, "C").Value = wsLookup.Cells(MatchedRow, "E").Value
End If
End If
Next iRow
End Sub

How to fix long run times replacing values

I have a spreadsheet with approx. 45,000 rows. Currently I am looping through a column and targeting any cells with a value of 0. Those row numbers get stored in an array. I am then looping through that array, and changing another cell based on the array value. I have 5000 rows with values that need to be reassigned, and it is taking over an hour to run that segment of the code (saving the row numbers to the array only takes a few seconds). Any ideas on how to get the code to run faster? Here is the code:
'Initialize array
Dim myArray() As Variant
Dim x As Long
'Looks for the last row on the "Dates" sheet
Dim lastRow As Long
With ThisWorkbook.Sheets("Dates")
lastRow = .Cells(.Rows.Count, "C").End(xlUp).Row + 1
End With
Dim i As Integer
i = 2
Dim uCounter As Integer
'Loop through all the dates on the "Dates" sheet
While i <= lastRow
'Each date has a counter next to it
uCounter = Worksheets("Dates").Range("B" & i).Value
Dim uDate As String
'Store the date as a string
uDate = Worksheets("Dates").Range("C" & i).Value
Dim startRow As Long, endRow As Long
'Finds the first and last instance of the date on the CERF Data page (45,000 rows)
With Sheets("CERF Data")
startRow = .Range("AN:AN").Find(what:=uDate, after:=.Range("AN1"), LookIn:=xlValues).Row
endRow = .Range("AN:AN").Find(what:=uDate, after:=.Range("AN1"), LookIn:=xlValues, searchdirection:=xlPrevious).Row
End With
Dim j As Long
For j = startRow To endRow
'If the cell in column BB is 0, and the counter is above 0 save row number to array, j being the variable representing row number
If Sheets("CERF Data").Range("BB" & j).Value = 0 And uCounter > 0 Then
'save row number to array
ReDim Preserve myArray(x)
myArray(x) = j
x = x + 1
'decrement counter by 1
uCounter = uCounter - 1
End If
If uCounter = 0 Then Exit For
Next j
i = i + 1
Wend
Dim y As Long
'Loop through the array and assign a value of 2 to all the rows in the array for column AS
For y = LBound(myArray) To UBound(myArray)
Sheets("CERF Data").Range("AS" & myArray(y)).Value = 2
Next y
Thanks!
Without more info this is what I can get you:
Just 1 loop through all the rows, once, checking both if the value on column BB = 0 and the date is within your range of dates:
Option Explicit
Sub Test()
Dim arr, i As Long, DictDates As Scripting.Dictionary
arr = ThisWorkbook.Sheets("CERF Data").UsedRange.Value
Set DictDates = New Scripting.Dictionary 'You need the Microsoft Scripting Runtime Reference for this to work
'Create a dictionary with all the dates you must check
With ThisWorkbook.Sheets("Dates")
LastRow = .Cells(.Rows.Count, 3).End(xlUp).Row
For i = 2 To LastRow
If Not DictDates.Exists(CDate(.Cells(i, 3))) Then DictDates.Add CDate(.Cells(i, 3)), 1
Next i
End With
'Only one loop through the whole array
For i = 1 To UBound(arr)
If arr(i, 54) = 0 And DictDates.Exists(CDate(arr(i, 40))) Then 'check your 2 criterias, date and value = 0
arr(i, 45) = 2 'input the value 2 on the column "AS"
End If
Next i
ThisWorkbook.Sheets("CERF Data").UsedRange.Value = arr
End Sub

For next Loop (beginner)

I want to copy gray cells to rows but only last column gray cell copied.
There's no need for nested loops
Sub Test()
Dim r As Integer, c As Integer
r = 3
For c = 3 To 21 Step 3
Cells(r, 1) = Cells(1, c)
r = r + 1
Next c
End Sub
You are so close :)
Option Explicit
Sub istebu()
Dim x As Long
Dim i As Long
For i = 3 To 10 'Loop in row from 3 to 10
For x = 3 To 21 Step 3 'Loop header row, from 3 to 21, jump 3
Cells(i, 1) = Cells(1, x) 'Copy values.
i = i + 1 'Add one row each time, so we don't overwrite previously row
Next x
Next i
End Sub
Alternative:
It could be shortened as we don't need to loop through the rows. We only need to add them. So we set i to the start row where we should paste our data.
Sub istebu()
Dim x As Long
Dim i As Long
i = 3 'Set first row number you want to loop from.
For x = 3 To 21 Step 3 'Loop header row, from 3 to 21, jump 3
Cells(i, 1) = Cells(1, x) 'Copy values.
i = i + 1 'Add one row each time, so we don't overwrite previously row
Next x
End Sub
There is an alternative to loops altogether.
Range("C1,F1,I1,L1,O1,R1,U1").Copy
Range("A3").PasteSpecial Paste:=xlPasteValues, Transpose:=True
But if you're really into loops, use one to build a union.
dim i as long, rng as range
for 3 to 21 step 3
if rng is nothing then
set rng = cells(1, i)
else
set rng = union(rng, cells(1, i))
end if
next i
rng.Copy
Range("A3").PasteSpecial Paste:=xlPasteValues, Transpose:=True

Copy and paste for a specific number of times

I have a column of data (F) and a column of numbers (G), and I want to copy each row of column F and paste to column H for a number of times, which depends on the corresponding value in column G.
How could I do it using vba?
For exemple:
F G H
4 Q7-CA 1 Q7-CA
5 Q5-CA 2 Q5-CA
6 A1-CA 1 Q5-CA
7 Q6-CA 4 A1-CA
8 BULK-TACEHU 1 Q6-CA
9 AMA-EG 2 Q6-CA
10 Q6-CA
11 Q6-CA
12 BULK-TACEHU
13 AMA-EG
14 AMA-EG
Use the code below, I used row 1 as the row where the data starts (modify according to your needs) :
Option Explicit
Sub CopyNumofTimes()
Dim LastRow As Long
Dim Sht As Worksheet
Dim lRow As Long
Dim newRow As Long
Dim CopyRep As Integer
Dim cpyRow As Integer
' modify Sheet1 to your Sheet name
Set Sht = ThisWorkbook.Sheets("Sheet1")
' modify 1 form the line number you are starting your data
newRow = 1
With Sht
' find last row with data in Column F
LastRow = .Cells(.Rows.Count, "F").End(xlUp).Row
For lRow = 1 To LastRow
CopyRep = .Cells(lRow, "G").Value
' make sure you have a number of at least 1 in Column G
If CopyRep > 0 Then
For cpyRow = 1 To CopyRep
.Cells(newRow, "H") = .Cells(lRow, "F")
newRow = newRow + 1
Next cpyRow
End If
Next lRow
End With
End Sub

VBA for duplicate rows

I have a sheet of columns.
I want to compare data in multiple columns, and return a flag in another column to indicate rows that are duplicates. I found a little code online which was meant for checking one column of data, and have so far been unsuccessful in being able to tweek it for multiple columns. The final code will need to look at specific columns which I will define later however for the moment say the sheet is as follows:
StaffNumber CallType
1 A
2 B
1 A
4 D
5 E
6 F
7 G
8 H
1 A
2 C
1 Z
6 P
The Col A is labelled Staff Number. Col B is labelled CallType. In Col C I want the flag to be entered against the row.
My Code is as follows:
Sub DuplicateIssue()
Dim last_StaffNumber As Long
Dim last_CallType As Long
Dim match_StaffNumber As Long
Dim match_CallType As Long
Dim StaffNumber As Long
Dim CallType As Long
last_StaffNumber = Range("A65000").End(xlUp).Row
last_CallType = Range("B65000").End(xlUp).Row
For StaffNumber = 1 To last_StaffNumber
For CallType = 1 To last_CallType
'checking if the Staff Number cell is having any item, skipping if it is blank.
If Cells(StaffNumber, 1) <> " " Then
'getting match index number for the value of the cell
match_StaffNumber = WorksheetFunction.Match(Cells(StaffNumber, 1), Range("A1:A" & last_StaffNumber), 0)
If Cells(CallType, 2) <> " " Then
match_CallType = WorksheetFunction.Match(Cells(CallType, 2), Range("B1:B" & last_CallType), 0)
'if the match index is not equals to current row number, then it is a duplicate value
If StaffNumber <> match_StaffNumber And CallType <> match_CallType Then
'Printing the label in the column C
Cells(StaffNumber, 3) = "Duplicate"
End If
End If
End If
Next
Next
End Sub
My problem is that only when Col 1 is a duplicate will the macro enter "Duplicate" into Col C, and it is not checking if the value of Col B is also the same.
Any Help would be much appreciated.
Try this code:
.
Option Explicit
Public Sub showDuplicateRows()
Const SHEET_NAME As String = "Sheet1"
Const LAST_COL As Long = 3 ' <<<<<<<<<<<<<<<<<< Update last column
Const FIRST_ROW As Long = 2
Const FIRST_COL As Long = 1
Const DUPE As String = "Duplicate"
Const CASE_SENSITIVE As Byte = 1 'Matches UPPER & lower
Dim includedColumns As Object
Set includedColumns = CreateObject("Scripting.Dictionary")
With includedColumns
.Add 1, "" ' <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< col 1 as dupe criteria
.Add 3, "" ' <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< col 3 as dupe criteria
End With
Dim searchRng As Range
Dim memArr As Variant
Dim i As Long
Dim j As Long
Dim unique As String
Dim totalRows As Long
Dim totalCols As Long
Dim totalURCols As Long
Dim valDict As Object
Set valDict = CreateObject("Scripting.Dictionary")
If CASE_SENSITIVE = 1 Then
valDict.CompareMode = vbBinaryCompare
Else
valDict.CompareMode = vbTextCompare
End If
With ThisWorkbook.Sheets(SHEET_NAME)
totalRows = .UsedRange.Rows.Count 'get last used row on sheet
totalURCols = .UsedRange.Columns.Count 'get last used col on sheet
Set searchRng = .Range( _
.Cells(FIRST_ROW, FIRST_COL), _
.Cells(totalRows, LAST_COL) _
)
If LAST_COL < totalURCols Then
.Range( _
.Cells(FIRST_ROW, LAST_COL + 1), _
.Cells(FIRST_ROW, totalURCols) _
).EntireColumn.Delete 'delete any extra columns
End If
End With
memArr = searchRng.Resize(totalRows, LAST_COL + 1) 'entire range with data to mem
For i = 1 To totalRows 'each row, without the header
For j = 1 To LAST_COL 'each col
If includedColumns.exists(j) Then
unique = unique & searchRng(i, j) 'concatenate values on same row
End If
Next
If valDict.exists(unique) Then 'check if entire row exists
memArr(i, LAST_COL + 1) = DUPE 'if it does, flag it in last col
Else
valDict.Add Key:=unique, Item:=i 'else add it to the dictionary
End If
unique = vbNullString
Next
searchRng.Resize(totalRows, LAST_COL + 1) = memArr 'entire memory back to the sheet
End Sub
.
Result:

Resources