Creating formulas linking cells in new worksheets created by the macro to summary sheet - excel

I am trying to copy a sheet and then in a separate summary sheet create formula’s that link to cells in this newly created copy.
I am not having much success which may be an issue with how I’ve identified and named the new sheet or with how I’ve constructed the formulas (or both).
Sub CopyCosting()
'
Dim currentNPD As String
Dim currentCOST As String
Dim currentCALC As String
Dim NewNPD As String
Dim NewCOST As String
Dim NewCALC As String
ActiveSheet.Select
currentNPD = ActiveSheet.Name
ActiveSheet.Next.Select
currentCOST = ActiveSheet.Name
ActiveSheet.Next.Select
currentCALC = ActiveSheet.Name
Sheets(Array(currentNPD, currentCOST, currentCALC)).Copy After:= _
Sheets("SUMMARY")
Worksheets("SUMMARY").Select
ActiveSheet.Next.Select
NewNPD = ActiveSheet.Name
ActiveSheet.Next.Select
NewCOST = ActiveSheet.Name
ActiveSheet.Next.Select
NewCALC = ActiveSheet.Name
Worksheets("SUMMARY").Select
NextFree = Range("B9:B" & Rows.Count).Cells.SpecialCells(xlCellTypeBlanks).Row
Range("A" & NextFree).EntireRow.Select
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
Range("B" & NextFree).Select
ActiveCell.FormulaR1C1 = _
"=NewCOST!R[-39]C[-1]&"" (""&NewCOST!R[-35]C[3]&""x""&NewCOST!R[-37]C[3]&""g)"""
ActiveCell.Offset(0, 1).Activate
ActiveCell.FormulaR1C1 = "=IF(NewCOST!R[-40]C[5]>49,""AYR"",""Seasonal"")"
End Sub
The excel formula #REFS and in relation to the first concatenate formula I ask the macro to create it looks as below:
=[NewCOST]NewCOST!A2&" ("&[NewCOST]NewCOST!E6&"x"&[NewCOST]NewCOST!E4&"g)"
I expect the formula to return text in the following format when R[-39]C[-1] = Cheese Cubes and R[-35]C[3] = 4 and R[-37]C[3] = 200
Cheese Cubes (4x200g)
I hope this all makes sense! Any help and advice would be greatly appreciated.

First, it is best to use the workbook and worksheet functions instead of select:
Dim wb as Workbook, ws as worksheet, nws as worksheet
Set wb = ActiveWorkbook
Set ws = wb.Worksheets("wsname")
set nws = wb.Worksheets("newws")'When you create new worksheet
Then you no longer need to use select when defining your range. Use:
ws.Range("...")
I would also try using the below for loop to interate through each cells formula, I would also write out the formula in excel and copy/paste in vba. Change the number with 'r':
For each r in Range("B" & NextFree)
'Formula here
Next r

Related

Pull data from certain WS and paste to another WS

Need help with my code please. I want to search all worksheets in a workbook that contain a specific string in its sheet name to copy cell data of a range and paste as values into a different ws. I keep getting Run-Time error '9' subscript out of range. It highlights Set wsSumm = ThisWorkbook.Sheets("Summary") as the reasoning. I have a Summary tab so I am unsure why it is giving this error.
What I ultimately need to do is take data from A2 of all BL ws and paste into Column A of Summary ws. Then take A1 of all SL ws and paste into Column B of Summary ws. I would need to paste as values. My sheets are named 1-15 as BL, SL (BL1, SL1, BL2, SL2, BL3, SL3, ect) and a Summary ws. Below is what my Workbook looks like and the Code I am using.
[enter image description here][1]
Option Explicit
Sub Macro1()
Dim wsSumm As Worksheet, ws As Worksheet
Dim strCol As String
Dim lngRow As Long
Application.ScreenUpdating = False
Set wsSumm = ThisWorkbook.Sheets("Summary") '<-Sheet name for the data to be concolidated. Change to suit.
For Each ws In ThisWorkbook.Sheets
If ws.Name <> wsSumm.Name Then
strCol = IIf(StrConv(Left(ws.Name, 2), vbUpperCase) = "BL", "A", "B")
lngRow = IIf(StrConv(Left(ws.Name, 2), vbUpperCase) = "BL", 2, 1)
wsSumm.Range(strCol & Rows.Count).End(xlUp).Offset(1, 0).Value = ws.Range("A" & lngRow)
End If
Next ws
Application.ScreenUpdating = True
End Sub

Populating new templates based on information in a list

Excel starts with two sheets.
First a list which includes data for a name, a number, and a product numbers.
The second tab is a template.
I'm trying to:
Copy the template tab, input the name, number, and product into the new tab, and then rename the tab (ActiveSheet.Name = Range("B3").Value).
Loop down to the next row and repeat until there are no more rows.
If a tab already exists with the name, then move onto the next row.
I tried two methods.
The code below I could probably figure out but it would require me to copy and paste the same lines with updated rows about 100 times since it isn't looping.
Also, the macro stops if there's already a tab with the name on it instead of continuing.
I made several attempts to have the macro move on if a tab has already been created from a name on the list but this keeps breaking the macro.
Sub TemplateMultiple()
'
' Tab creation and naming
'
'
Sheets("Template").Select
Sheets("Template").Copy Before:=Sheets(2)
Range("B3:C3").Select
ActiveCell.FormulaR1C1 = "='List'!R[2]C"
Range("B5:C5").Select
ActiveCell.FormulaR1C1 = "='List'!RC[3]"
Range("B6:C6").Select
ActiveCell.FormulaR1C1 = "='List'!R[-1]C[4]"
Range("B7:C7").Select
ActiveSheet.Name = Range("B3").Value
Sheets("Template").Select
Sheets("Template").Copy Before:=Sheets(3)
Range("B3:C3").Select
ActiveCell.FormulaR1C1 = "='List'!R[3]C"
Range("B5:C5").Select
ActiveCell.FormulaR1C1 = "='List'!R[2]C[3]"
Range("B6:C6").Select
ActiveCell.FormulaR1C1 = "='List'!R[0]C[4]"
Range("B7:C7").Select
ActiveSheet.Name = Range("B3").Value
Sheets("Template").Select
Sheets("Template").Copy Before:=Sheets(4)
Range("B3:C3").Select
ActiveCell.FormulaR1C1 = "='List'!R[4]C"
Range("B5:C5").Select
ActiveCell.FormulaR1C1 = "='List'!R[2]C[3]"
Range("B6:C6").Select
ActiveCell.FormulaR1C1 = "='List'!R[1]C[4]"
Range("B7:C7").Select
ActiveSheet.Name = Range("B3").Value
Sheets("Template").Select
Sheets("Template").Copy Before:=Sheets(5)
Range("B3:C3").Select
ActiveCell.FormulaR1C1 = "='List'!R[5]C"
Range("B5:C5").Select
ActiveCell.FormulaR1C1 = "='List'!R[3]C[3]"
Range("B6:C6").Select
ActiveCell.FormulaR1C1 = "='List'!R[2]C[4]"
Range("B7:C7").Select
ActiveSheet.Name = Range("B3").Value
Sheets("Template").Select
Sheets("Template").Copy Before:=Sheets(6)
Range("B3:C3").Select
ActiveCell.FormulaR1C1 = "='List'!R[6]C"
Range("B5:C5").Select
ActiveCell.FormulaR1C1 = "='List'!R[4]C[3]"
Range("B6:C6").Select
ActiveCell.FormulaR1C1 = "='List'!R[3]C[4]"
Range("B7:C7").Select
ActiveSheet.Name = Range("B3").Value
End Sub
The second method involves a loop to make the code much easier to read/follow.
My code is putting the same information into each template instead of going down one row for each spreadsheet.
Sub Template1()
'UpdatebyExtendoffice20161222
Dim x As Integer
Application.ScreenUpdating = False
' Set numrows = number of rows of data.
NumRows = Range("B5", Range("B5").End(xlDown)).Rows.Count
' Select cell a1.
Range("B5").Select
' Establish "For" loop to loop "numrows" number of times.
For x = 1 To NumRows
' Insert your code here.
Sheets("Template").Select
Sheets("Template").Copy Before:=Sheets(2)
Range("B3:C3").Select
ActiveCell.FormulaR1C1 = "='List'!R[2]C"
Range("B5:C5").Select
ActiveCell.FormulaR1C1 = "='List'!RC[3]"
Range("B6:C6").Select
ActiveCell.FormulaR1C1 = "='List'!R[-1]C[4]"
Range("B7:C7").Select
ActiveSheet.Name = Range("B3").Value
' Selects cell down 1 row from active cell.
ActiveCell.Offset(1, 0).Select
Next
Application.ScreenUpdating = True
End Sub
Something like this should work:
Sub Template1()
Dim wb As Workbook, ws As Worksheet, wsList As Worksheet
Dim c As Range, sheetName As String, wsTempl As Worksheet
Set wb = ThisWorkbook
Set wsList = wb.Worksheets("List")
Set wsTempl = wb.Worksheets("Template")
Application.ScreenUpdating = False
For Each c In wsList.Range("B5", wsList.Cells(Rows.Count, "B").End(xlUp)).Cells
sheetName = c.Value
Set ws = GetWorksheet(wb, sheetName) 'see if there's an existing sheet with this name
If ws Is Nothing Then 'if was no matching sheet
wsTempl.Copy before:=wsTempl 'copy template in front of itself
Set ws = wb.Worksheets(wsTempl.Index - 1) 'get a reference to the copy
ws.Name = sheetName
With c.EntireRow
'I never use R1C1 so this might be off...
ws.Range("B3:C3").Formula = "='List'!" & .Columns("B").Address(False, False)
ws.Range("B5:C5").Formula = "='List'!" & .Columns("E").Address(False, False)
ws.Range("B6:C6").Formula = "='List'!" & .Columns("E").Address(False, False)
End With
End If
Next c
Application.ScreenUpdating = True
End Sub
'Return a worksheet named `wsName` from workbook `wb`, or `Nothing` if it doesn't exist
Function GetWorksheet(wb As Workbook, wsName As String) As Worksheet
On Error Resume Next
Set GetWorksheet = wb.Worksheets(wsName)
On Error Goto 0
End Function
Note there's rarely any need to select/activate things before you work with them - that's an artifact of the macro recorder.
See How to avoid using Select in Excel VBA for more on this and some good guidelines to follow.

Code modification to copy all data in a row or the whole row instead of only copying a cell

New VBA user here, the below code matches the 1st column in a worksheet with the 1st column in another worksheet using vlookup then copies the first cell from 1st to 2nd as the screenshots.
Code
Sub solution()
Dim oldRow As Integer
Dim newRow As Integer
Dim lrow_output As Integer 'variable indicating last fulfilled row
Dim WB_Input As Workbook
Dim WB_Output As Workbook
Dim WS_Input As Worksheet
Dim WS_Output As Worksheet
Dim funcStr As String
Set WB_Input = Workbooks("input")
Set WB_Output = Workbooks("output1")
Set WS_Input = WB_Input.Worksheets("input")
Set WS_Output = WB_Output.Worksheets("Sheet1")
With WS_Output
lrow_output = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
With WS_Input
funcStr = "=IFERROR(VLOOKUP(" & Cells(1, 1).Address(False, False) & "," & "'[" & WB_Input.Name & "]" & .Name & "'!" & Range(.Columns(1), .Columns(2)).Address & ",2,0),"""")"
End With
With WS_Output
.Cells(1, 2).Formula = funcStr
.Cells(1, 2).Copy
Range(.Cells(1, 2), .Cells(lrow_output, 2)).PasteSpecial xlPasteFormulas
WS_Output.Calculate
Range(.Cells(1, 2), .Cells(lrow_output, 2)).Copy
Range(.Cells(1, 2), .Cells(lrow_output, 2)).PasteSpecial xlPasteValues
Application.CutCopyMode = False
End With
End Sub
Problem: I need the code to copy and paste the all data in the row, not just the first cell.
Problem2:If possible I need the code to scan multiple sheets, not just one so it would be 1 input main workbook sheet and 4 output sheets in the output workbook.
Problem3(Optional): if possible I need the successfully matched and copied rows in the input workbook to be colored to tell them from the unsuccessful matches.
Thank you in advance, I really appreciate all the possible aid.
Here is a quick macro that will take the active cell row copy it and then select specified sheet and paste it in active cell row:
Sub CopyPaste()
'
' CopyPaste Macro
'
'
ActiveCell.Rows("1:1").EntireRow.Select
Selection.Copy
Sheets("Sheet#").Select
ActiveCell.Rows("1:1").EntireRow.Select
ActiveSheet.Paste
End Sub

Copy and paste values only after filtering data in vba [duplicate]

I have two sheets. One has the complete data and the other is based on the filter applied on the first sheet.
Name of the data sheet : Data
Name of the filtered Sheet : Hoky
I am just taking a small portion of data for simplicity. MY objective is to copy the data from Data Sheet, based on the filter. I have a macro which somehow works but its hard-coded and is a recorded macro.
My problems are:
The number of rows is different everytime. (manual effort)
Columns are not in order.
Sub TESTTHIS()
'
' TESTTHIS Macro
'
'FILTER
Range("F2").Select
Selection.AutoFilter
ActiveSheet.Range("$B$2:$F$12").AutoFilter Field:=5, Criteria1:="hockey"
'Data Selection and Copy
Range("C3").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Sheets("Hockey").Select
Range("E3").Select
ActiveSheet.Paste
Sheets("Data").Select
Range("D3").Select
Range(Selection, Selection.End(xlDown)).Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Hockey").Select
Range("D3").Select
ActiveSheet.Paste
Sheets("Data").Select
Range("E3").Select
Range(Selection, Selection.End(xlDown)).Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Hockey").Select
Range("C3").Select
ActiveSheet.Paste
End Sub
Best way of doing it
Below code is to copy the visible data in DBExtract sheet, and paste it into duplicateRecords sheet, with only filtered values. Range selected by me is the maximum range that can be occupied by my data. You can change it as per your need.
Sub selectVisibleRange()
Dim DbExtract, DuplicateRecords As Worksheet
Set DbExtract = ThisWorkbook.Sheets("Export Worksheet")
Set DuplicateRecords = ThisWorkbook.Sheets("DuplicateRecords")
DbExtract.Range("A1:BF9999").SpecialCells(xlCellTypeVisible).Copy
DuplicateRecords.Cells(1, 1).PasteSpecial
End Sub
I suggest you do it a different way.
In the following code I set as a Range the column with the sports name F and loop through each cell of it, check if it is "hockey" and if yes I insert the values in the other sheet one by one, by using Offset.
I do not think it is very complicated and even if you are just learning VBA, you should probably be able to understand every step. Please let me know if you need some clarification
Sub TestThat()
'Declare the variables
Dim DataSh As Worksheet
Dim HokySh As Worksheet
Dim SportsRange As Range
Dim rCell As Range
Dim i As Long
'Set the variables
Set DataSh = ThisWorkbook.Sheets("Data")
Set HokySh = ThisWorkbook.Sheets("Hoky")
Set SportsRange = DataSh.Range(DataSh.Cells(3, 6), DataSh.Cells(Rows.Count, 6).End(xlUp))
'I went from the cell row3/column6 (or F3) and go down until the last non empty cell
i = 2
For Each rCell In SportsRange 'loop through each cell in the range
If rCell = "hockey" Then 'check if the cell is equal to "hockey"
i = i + 1 'Row number (+1 everytime I found another "hockey")
HokySh.Cells(i, 2) = i - 2 'S No.
HokySh.Cells(i, 3) = rCell.Offset(0, -1) 'School
HokySh.Cells(i, 4) = rCell.Offset(0, -2) 'Background
HokySh.Cells(i, 5) = rCell.Offset(0, -3) 'Age
End If
Next rCell
End Sub
When i need to copy data from filtered table i use range.SpecialCells(xlCellTypeVisible).copy. Where the range is range of all data (without a filter).
Example:
Sub copy()
'source worksheet
dim ws as Worksheet
set ws = Application.Worksheets("Data")' set you source worksheet here
dim data_end_row_number as Integer
data_end_row_number = ws.Range("B3").End(XlDown).Row.Number
'enable filter
ws.Range("B2:F2").AutoFilter Field:=2, Criteria1:="hockey", VisibleDropDown:=True
ws.Range("B3:F" & data_end_row_number).SpecialCells(xlCellTypeVisible).Copy
Application.Worksheets("Hoky").Range("B3").Paste
'You have to add headers to Hoky worksheet
end sub
it needs to be .Row.count not Row.Number?
That's what I used and it works fine
Sub TransfersToCleared()
Dim ws As Worksheet
Dim LastRow As Long
Set ws = Application.Worksheets("Export (2)") 'Data Source
LastRow = Range("A" & Rows.Count).End(xlUp).Row
ws.Range("A2:AB" & LastRow).SpecialCells(xlCellTypeVisible).Copy

copy, count and order all the words of a specific column and move them to other sheet

What I am trying to achieve is to copy the unique words (they repeat a few times) of sheet "Data" column A (ignoring header) to sheet "Country" column A and then add a second column to this sheet with the counting of occurrences of every word found. At same time ordering the list from higher to smaller. See the prints below as example.
Sheet "Data":
Sheet "Country" and the output i want to accomplish:
What I have so far, but not working (givin' error):
Sub Count_Sort()
Dim lastRow As Integer
Dim ws As String
Dim c As Range
ws = ActiveSheet.Name
lastRow = LastUsedRow
Range("A1").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Sheets.Add After:=Sheets(Sheets.Count)
ActiveSheet.Paste
Application.CutCopyMode = False
ActiveSheet.Range("$A$1:$A$" & lastRow).RemoveDuplicates Columns:=1, Header:=xlNo
ActiveSheet.Name = "Country"
Sheets(ws).Activate
Set c = Range("A1")
Set d = Sheets("Country").Range("A1")
Do While Not IsEmpty(c)
Do While Not IsEmpty(d)
If c.Value = d.Value Then
d.Offset(0, 1).Value = d.Offset(0, 1).Value + 1
Set d = d.Offset(1, 0)
Exit Do
End If
Set d = d.Offset(1, 0)
Loop
Set c = c.Offset(1, 0)
Set d = Sheets("Country").Range("A1")
Loop
End Sub
Public Function LastUsedRow()
LastUsedRow = [A65536].End(xlUp).Row
End Function
Any help would be most welcome...
Ps. I intend to do the same to all the columns of sheet "Data" (around 20), copy to a different sheet and then count and order each word. But if i manage to this in one, i think i will get to the others. Thanks again.
Keeping the general structure of your code:
Sub Count_Sort()
Dim i As Integer
Dim ws As Worksheet, cs As Worksheet
Set ws = Sheets("Data")
ws.Select
ws.Range("A2", ws.Range("A2").End(xlDown)).Select 'Update for different data column
Selection.Copy
Sheets.Add After:=Sheets(Sheets.Count)
ActiveSheet.Name = "Country" 'Update for different data column
Set cs = Sheets("Country") 'Update for different data column
cs.Range("A2").Select
cs.Paste
Application.CutCopyMode = False
cs.Range("A2", cs.Range("A2").End(xlDown)).RemoveDuplicates Columns:=1, Header:=xlNo
cs.Range("A1") = ws.Range("A1").Value 'Update for different data column (only ws.Range("A1").Value) (this is just the column heading)
cs.Range("B1") = "X times"
For i = 1 To cs.Range("A2", cs.Range("A2").End(xlDown).End(xlUp)).Rows.Count
cs.Cells(1 + i, 2) = Application.CountIf(ws.Range("A2", ws.Range("A2").End(xlDown)), cs.Cells(1 + i, 1)) 'Update for different data column
Next i
cs.Range(cs.Cells(2, 1), cs.Cells(cs.Range("A2").End(xlDown).Row, 2)).Sort Key1:=cs.Range("B1"), order1:=xlDescending, Header:=xlNo
End Sub
You can then just change the references for the different columns and/or worksheets.
Additionally, you should consider adding some error handling or checks to make sure your code doesn't crash if the sheet you are adding exists.
This is very easy to do without any VBA at all, using excel's built-in functions and techniques. However, since it seems you have many to do, I would like to suggest using VBA to utilize Excels existing tools to help you do the work faster (and with less code):
Also, it's best practice to avoid using .Select and .Active statements as much as possible.
Sub Count_Sort()
Dim lastRow As Integer
Dim ws As Worksheet, wsA As Worksheet
Set ws = Sheets("Data") 'ActiveSheet.Name ... better to use actual sheet name
Set wsA = Sheets.Add(After:=Sheets(Sheets.Count))
With ws
lastRow = LastUsedRow
.Range("B2:A" & lastRow).AdvancedFilter Action:=xlFilterCopy, CopyToRange:=wsA.Range("A1"), Unique:=True
End With
With wsA
.Name = "Country"
With .Range("B2")
.Formula = "=Countif(" & ws.Name & "!A:A,A2)"
.AutoFill wsA.Range("A1").End(xlDown).Offset(, 1)
End With
End With
End Sub
Public Function LastUsedRow()
LastUsedRow = [A65536].End(xlUp).Row
End Function

Resources