Remove duplicates from range and use in for each loop - vba

I want to create worksheets from a list in excel using VBA, I have the below code which works fine. But it doesn't remove duplicates from the list, and if I use remove duplicates, it throws an error. :). I don't want the original column altered.
Set MyRange = Sheets("YES").Range("A2")
Set MyRange = Range(MyRange, MyRange.End(xlDown)).RemoveDuplicates
For Each MyCell In MyRange
Sheets.Add After:=Sheets(Sheets.Count) ' creates a new worksheet
Sheets(Sheets.Count).Name = UCase(MyCell.Value) ' renames the new worksheet
ActiveSheet.Range("A1").Select ' selects current worksheet
Cells(1, 1).Font.Bold = True ' changes fornt to bold
ActiveCell.Value = ("Column Name") ' enters values into cell
ActiveSheet.Range("A2").Select
ActiveCell.Value = UCase(MyCell.Value) ' enters column name in cell
Next MyCell
thanks

How about this code. It will leave the original column in tact and remove the dupes in a holding range. It's also qualified more cleanly.
Dim wsYes as Worksheet
Set wsYes = Worksheets("YES")
With wsYes
Dim myRange as Range
Set myRange = .Range("A2",.Range("A2").End(xlDown))
myRange.Copy .Cells(1,.Columns.Count) 'copy to far right column
.Cells(1,.Columns.Count).Resize(myRange.Rows.Count,1).RemoveDuplicates 1, xlNo
Set myRange = .Range(.Cells(1,.Columns.Count),.Cells(1,.Columns.Count).End(XlDown))
For Each MyCell In myRange
Dim sName as String
sName = UCase(MyCell.Value)
Dim wsNew as Worksheet
Set wsNew = Sheets.Add(After:=Sheets(Sheets.Count)) ' creates a new worksheet
With wsNew
.Name = sName
.Range("A1").Value = "Column Name"
.Range("A1").Font.Bold = True
.Range("A2").Value = sName
End With
Next MyCell
myRange.Clear
End with

Easy way (but not the best I think if you have many data):
Set MyRange = Sheets("YES").Range("A2")
Set MyRange = Range(MyRange, MyRange.End(xlDown))
Dim index1 As Integer
Dim index2 As Integer
index1 = 0
For Each Cell1 In MyRange
index1 = index1 + 1
index2 = 0
For Each Cell2 In MyRange
If index2 >= index1
Then Exit For
If MyCell.Value = Cell2.Value
Then Goto NextCell1
Next Cell2
Sheets.Add After:=Sheets(Sheets.Count) ' creates a new worksheet
Sheets(Sheets.Count).Name = UCase(MyCell.Value) ' renames the new worksheet
ActiveSheet.Range("A1").Select ' selects current worksheet
Cells(1, 1).Font.Bold = True ' changes fornt to bold
ActiveCell.Value = ("Column Name") ' enters values into cell
ActiveSheet.Range("A2").Select
ActiveCell.Value = UCase(MyCell.Value) ' enters column name in cell
NextCell1:
Next Cell1

Related

Macro to copy sheet from list error

I have created a macro to create worksheets from a list,this works fine but i have a problem, if i only have one item in the list i get an error, here is the macro:
Sub CreateSheetsFromAList()
Application.ScreenUpdating = False
Sheets("Master").Select
Sheets("Stock Removal").Visible = True
Dim MyCell As Range, MyRange As Range
Set MyRange = Sheets("Master").Range("A14")
Set MyRange = Range(MyRange, MyRange.End(xlDown))
For Each MyCell In MyRange
Sheets("Stock Removal").Copy after:=Sheets(Sheets.Count) 'creates a new worksheet
Sheets(Sheets.Count).Name = MyCell.Value ' renames the new worksheet
Next MyCell
Sheets("Stock Removal").Select
ActiveWindow.SelectedSheets.Visible = False
Application.ScreenUpdating = True
End Sub
You should rather use xlUp than xlDown, it is safer!
You selected the whole column previously (from row 14, until the end of the sheet!)
This will run smoothly! ;)
Sub CreateSheetsFromAList()
Application.ScreenUpdating = False
Dim wsM As Worksheet, wsSR As Worksheet
Dim MyCell As Range, MyRange As Range, LastRow As Double
Set wsM = ThisWorkbook.Sheets("Master")
Set wsSR = ThisWorkbook.Sheets("Stock Removal")
wsM.Select
wsSR.Visible = True
Set MyRange = wsM.Range("A14")
LastRow = wsM.Range("A" & wsM.Rows.Count).End(xlUp).Row
If LastRow > 14 Then
Set MyRange = Range(MyRange, MyRange.End(xlDown))
For Each MyCell In MyRange
wsSR.Copy after:=Sheets(Sheets.Count) 'creates a new worksheet
Sheets(Sheets.Count).Name = MyCell.Value ' renames the new worksheet
Next MyCell
Else
wsSR.Copy after:=Sheets(Sheets.Count) 'creates a new worksheet
Sheets(Sheets.Count).Name = MyRange.Value ' renames the new worksheet
End If
wsSR.Select
ActiveWindow.SelectedSheets.Visible = False
Application.ScreenUpdating = True
End Sub
The problem is in case if only Cell A14 has data, and the entire column A (below cell A14) is blank, in that case MyRange.End(xlDown) will result in "A1048576". So you need to find the last row in Column A, and then check if it's 14 >> If it is then your MyRange should consist of 1 cell, and that's Cell A14.
Try the code below to replace the way you Set MyRange :
With Sheets("Master")
If .Cells(.Rows.Count, "A").End(xlUp).Row = 14 Then ' if only cell A14 has data in entire Column A
Set MyRange = Sheets("Master").Range("A14")
Else
Set MyRange = Sheets("Master").Range("A14", Range("A14").End(xlDown))
End If
End With
Try with changing:
Set MyRange = Sheets("Master").Range("A14")
Set MyRange = Range(MyRange, MyRange.End(xlDown))
To:
With Sheets("Master")
Set MyRange = .Range(Range("A14"), .Range("A" & .Range("A" & .Rows.Count).End(xlUp).row))
End With

VBA - Macro for copy sheets, insert formulas and change row reference by +1

I have macro for copy one sample sheet. Numbers of sheets copies are based by different sheet values. I need insert different formulas for every copy to specific range, where row number of formula is elevated by +1. Is it possible to do this?
Example what I need:
- Sheet1 "=DATA_SELECTED!$N$2"
- Sheet2 "=DATA_SELECTED!$N$3"
- Sheet3 "=DATA_SELECTED!$N$4"
This is what I have right now without +1 in formulas.
Sub CopySheetsFromAList()
Dim MyCell As Range, MyRange As Range
Set MyRange = Sheets("DATA").Range("A1")
Set MyRange = Range(MyRange, MyRange.End(xlDown))
Set ws = Sheets("Sheet1")
For Each MyCell In MyRange
ws.Copy after:=Sheets(Sheets.Count)
Sheets(Sheets.Count).Name = MyCell.Value
Sheets(Sheets.Count).Range("C3").Formula = "=DATA_SELECTED!$M$2"
Sheets(Sheets.Count).Range("C4").Formula = "=DATA_SELECTED!$N$2"
Sheets(Sheets.Count).Range("C6").Formula = "=DATA_SELECTED!$K$2"
Sheets(Sheets.Count).Range("C7").Formula = "=DATA_SELECTED!$Y$2"
Next MyCell
End Sub
maybe something like this
Option Explicit
Sub CopySheetsFromAList()
Dim MyCell As Range, MyRange As Range
Dim ws As Worksheet
Dim iRow As Long
Set MyRange = Sheets("DATA").Range("A1")
Set MyRange = Range(MyRange, MyRange.End(xlDown))
Set ws = Sheets("Sheet1")
For Each MyCell In MyRange
ws.Copy after:=Sheets(Sheets.Count)
iRow = iRow + 1
With Sheets(Sheets.Count)
.Name = MyCell.Value
.Range("C3").Formula = "=DATA_SELECTED!$M$" & (1 + iRow)
.Range("C4").Formula = "=DATA_SELECTED!$N$" & (1 + iRow)
.Range("C6").Formula = "=DATA_SELECTED!$K$" & (1 + iRow)
.Range("C7").Formula = "=DATA_SELECTED!$Y$" & (1 + iRow)
End With
Next MyCell
End Sub

Filter sheet, and copy selection onto new sheet using VBA

Trying to filter and then copy the filtered cells in a loop, getting the error message " paste method of worksheet class failed".
It seems to fail because I am using a loop, ive tried other methods of paste special but this doesn't seem to work, please help
Sub Split()
Dim wsYes As Worksheet
Set wsYes = Worksheets("YES")
With wsYes
Dim myRange As Range
Set myRange = .Range("A2", .Range("A2").End(xlDown))
myRange.Copy .Cells(1, .Columns.Count) 'copy to far right column
.Cells(1, .Columns.Count).Resize(myRange.Rows.Count, 1).RemoveDuplicates 1, xlNo
Set myRange = .Range(.Cells(1, .Columns.Count), .Cells(1, .Columns.Count).End(xlDown))
For Each MyCell In myRange
Dim sName As String
sName = UCase(MyCell.Value)
Range("A1").Select
Selection.AutoFilter
ActiveSheet.Range("$A$1:$B$9").AutoFilter Field:=1, Criteria1:= _
sName
Range("B:B").Select
Selection.Copy
Dim wsNew As Worksheet
Set wsNew = Sheets.Add(After:=Sheets(Sheets.Count)) ' creates a new worksheet
wsYes.Range("B:B").Copy
With wsNew
.Name = sName
.Range("A1").Value = "Column Name"
.Range("A1").Font.Bold = True
.Range("A2").Value = sName
.Range("B1").Select
ActiveSheet.Paste
End With
Next MyCell
myRange.Clear
End With
End Sub
Thanks in advance
You need to have Copy and Paste together, not doing other stuff on wsNew sheet
Sub Split()
Dim wsYes As Worksheet
Set wsYes = Worksheets("YES")
With wsYes
Dim myRange As Range
Set myRange = .Range("A2", .Range("A2").End(xlDown))
myRange.Copy .Cells(1, .Columns.Count) 'copy to far right column
.Cells(1, .Columns.Count).Resize(myRange.Rows.Count, 1).RemoveDuplicates 1, xlNo
Set myRange = .Range(.Cells(1, .Columns.Count), .Cells(1, .Columns.Count).End(xlDown))
For Each MyCell In myRange
Dim sName As String
sName = UCase(MyCell.Value)
wsYes.Select
Range("A1").Select
Selection.AutoFilter
ActiveSheet.Range("$A$1:$B$9").AutoFilter Field:=1, Criteria1:=sName
wsYes.Range("B:B").Select
Selection.Copy
Dim wsNew As Worksheet
Set wsNew = Sheets.Add(After:=Sheets(Sheets.Count)) ' creates a new worksheet
With wsNew
.Name = sName
.Range("A1").Value = "Column Name"
.Range("A1").Font.Bold = True
.Range("A2").Value = sName
' moved copy and paste tasks one after the other
wsYes.Range("B:B").Copy
.Columns("B:B").Select
ActiveSheet.Paste
End With
Next MyCell
myRange.Clear
End With
End Sub
Try this code.
Sub Split()
Dim MyCell As Range
Dim wsYes As Worksheet
Set wsYes = Worksheets("YES")
With wsYes
Dim myRange As Range
Set myRange = .Range("A2", .Range("A2").End(xlDown))
myRange.Copy .Cells(1, .Columns.Count) 'copy to far right column
.Cells(1, .Columns.Count).Resize(myRange.Rows.Count, 1).RemoveDuplicates 1, xlNo
Set myRange = .Range(.Cells(1, .Columns.Count), .Cells(1, .Columns.Count).End(xlDown))
For Each MyCell In myRange
Dim sName As String
sName = UCase(MyCell.Value)
With wsYes
.Range("A1").Select
.Selection.AutoFilter
.Range("$A$1:$B$9").AutoFilter Field:=1, Criteria1:=sName
Dim wsNew As Worksheet
Set wsNew = Sheets.Add(After:=Sheets(Sheets.Count)) ' creates a new worksheet
End With
With wsNew
.Name = sName
.Range("A1").Value = "Column Name"
.Range("A1").Font.Bold = True
.Range("A2").Value = sName
.Range("B1").Select
wsYes.Range("B:B").Copy
ActiveSheet.Paste
End With
Next MyCell
myRange.Clear
End With
End Sub
It seems like after making A1 bold it was clearing a buffer so you had nothing copied.

Excel datasheet entry inserting as single row, not multiple

The script is doing exactly what I need it to do, but it's inserting the input range (A7:B30) into a single row, rather than the existing format.
Sub UpdateLogWorksheet()
'http://www.contextures.com/xlForm02.html
Dim dataWks As Worksheet
Dim inputWks As Worksheet
Dim nextRow As Long
Dim oCol As Long
Dim myRng As Range
Dim myCopy As String
Dim myCell As Range
'cells to copy from Input sheet - some contain formulas
myCopy = "A7:B30"
Set inputWks = Worksheets("Input")
Set dataWks = Worksheets("Data")
With dataWks
nextRow = .Cells(.Rows.Count, "A").End(xlUp).Offset(1, 0).Row
End With
With inputWks
Set myRng = .Range(myCopy)
End With
With dataWks
With .Cells(nextRow, "A")
.Value = ""
.NumberFormat = "dd/mm/yyyy"
End With
.Cells(nextRow, "D").Value = "HELLO"
oCol = 3
For Each myCell In myRng.Cells
dataWks.Cells(nextRow, oCol).Value = myCell.Value
oCol = oCol + 1
Next myCell
End With
'clear input cells that contain constants
With inputWks
On Error Resume Next
With .Range(myCopy).Cells.SpecialCells(xlCellTypeConstants)
.ClearContents
Application.GoTo .Cells(1) ', Scroll:=True
End With
On Error GoTo 0
End With
End Sub
Any ideas?
Try changing:
For Each myCell In myRng.Cells
dataWks.Cells(nextRow, oCol).Value = myCell.Value
oCol = oCol + 1
Next myCell
to
For Each myCell In myRng.Cells
dataWks.Range(myCell.Address).Value = myCell.Value
Next myCell
That will preserve the layout, i.e. the data will be pasted into the same range it was copied from.

Excel VBA Dynamic Ranges

I'm looking to improve my code to dynamically set ranges where data exist instead of hard coding the values. The starting value of the range will never change, but the ending value will if more month columns are added. What is the best way to approach this. Would be easier to make the range user defined?
Here's what I have:
The code will split data by unique group name starting at C5 into separate worksheets.
Public Sub Splitdatatosheets()
' Splitdatatosheets Macro
Dim Rng As Range
Dim Rng1 As Range
Dim vrb As Boolean
Dim sht As Worksheet
'Find unique value for splitting
Set Rng = Sheets("Sheet1").Range("C5")
'Find starting row to copy (Re-code to dynamically set)
Set Rng1 = Sheets("Sheet1").Range("A5:M5")
vrb = False
Do While Rng <> ""
For Each sht In Worksheets
If sht.Name = Left(Rng.Value, 31) Then
sht.Select
Range("A2").Select
Do While Selection <> ""
ActiveCell.Offset(1, 0).Activate
Loop
Rng1.Copy ActiveCell
ActiveCell.Offset(1, 0).Activate
Set Rng1 = Rng1.Offset(1, 0)
Set Rng = Rng.Offset(1, 0)
vrb = True
End If
Next sht
If vrb = False Then
Sheets.Add After:=Sheets(Sheets.Count)
ActiveSheet.Name = Left(Rng.Value, 31)
'Copy header rows (Re-code to dynamically set) to new worksheet first cell
Sheets("Sheet1").Range("A4:M4").Copy ActiveSheet.Range("A1")
Range("A2").Select
Do While Selection <> ""
ActiveCell.Offset(1, 0).Activate
Loop
Rng1.Copy ActiveCell
Set Rng1 = Rng1.Offset(1, 0)
Set Rng = Rng.Offset(1, 0)
End If
vrb = False
Loop
End Sub
Here's the updated code for anyone who stumbles across this question.
Public Sub Splitdatatosheets()
' Splitdatatosheets Macro
Dim rng As Range
Dim Rng1 As Range
Dim Rng2 As Range
Dim vrb As Boolean
Dim sht As Worksheet
Dim R_Start, R_End, H_Start, H_End As Range
'Set Header
Set H_Start = Cells(4, 1)
Set H_End = H_Start.End(xlToRight)
'Set Data range
Set R_Start = Cells(5, 1)
Set R_End = R_Start.End(xlToRight)
'Find unique value for splitting
Set rng = Sheets("Sheet1").Range("C5")
'Find starting row to copy
Set Rng1 = Range(R_Start, R_End)
Set Rng2 = Range(H_Start, H_End)
vrb = False
Do While rng <> ""
For Each sht In Worksheets
If sht.Name = Left(rng.Value, 31) Then
sht.Select
Range("A2").Select
Do While Selection <> ""
ActiveCell.Offset(1, 0).Activate
Loop
Rng1.Copy ActiveCell
ActiveCell.Offset(1, 0).Activate
Set Rng1 = Rng1.Offset(1, 0)
Set rng = rng.Offset(1, 0)
vrb = True
End If
Next sht
If vrb = False Then
Sheets.Add After:=Sheets(Sheets.Count)
ActiveSheet.Name = Left(rng.Value, 31)
'Copy header rows to new worksheet first cell
Rng2.Copy ActiveSheet.Range("A1")
Range("A2").Select
Rng1.Copy ActiveCell
Set Rng1 = Rng1.Offset(1, 0)
Set rng = rng.Offset(1, 0)
End If
vrb = False
Loop
End Sub