Excel VBA Array list - vba

I am a toddler in VBA
I have a large range this could be more than 1000 text values (This could be going down A1), I am trying to concatenate all values with quote and comma into one cell (C1), i know of the transpose formula, but I am not sure my vba array will recognise this as a list.
I am keen for my array formula to recognize c1 as list, in order to carry out my action.
I am really keen to keep this clean and not use the concatenation and drag various formulas down.
I came across this, but this does not paste all the values into one cell.
Sub transpose()
Dim rng As Range
Dim ws As Worksheet
Dim last As Range
Set ws = ActiveSheet
Set last = ws.Cells(Rows.Count, "A").End(xlUp)
Set rng = ws.Range("A1", last)
For Each cell In rng
Dim hold As String
hold = """"
hold = hold + cell.Value
hold = hold + """" + ", "
cell.Value = hold
Next cell
rng.Copy
ActiveWorkbook.Sheets(2).Range("A1").PasteSpecial transpose:=True
End Sub
Code done by ryan E
If anyone can suggest any cheats on gathering list for Arrays that would be great. Other than using the Macro tool in excel
Example.
A1 = company1
A2 = company2
etc
Solution
C1 would show in one cell "company1", "company2", .... "company10000"

You can use Join() and Transpose().
For example:
Sub transpose()
Dim rng As Range
Dim ws As Worksheet
Dim last As Range
Set ws = ActiveSheet
Set last = ws.Cells(Rows.Count, "A").End(xlUp)
Set rng = ws.Range(ws.Range("A1"), last)
ws.Range("B1").Value = """" & Join(Application.Transpose(rng.Value), """,""") & """"
End Sub
EDIT: now I see what you really want to do (create an array of sheet names to pass to Sheets.Copy()) here's one approach...
Add a sheet named (eg) "Groups" to hold your various lists of sheets to be copied:
Group names are in Row 1, with a list of sheets below each name.
Then use this code:
'to demo the "CopySheets()" sub...
Sub Tester()
CopySheets "Group2" 'copy all sheets in Group2
End Sub
'Create of copy for all sheets under "GroupName" header...
Sub CopySheets(GroupName As String)
Dim rng As Range, arr
Dim ws As Worksheet
Dim f As Range
Set ws = ThisWorkbook.Sheets("Groups") '<< has lists of sheet names
'find the header for the group to be copied
Set f = ws.Rows(1).Find(GroupName, lookat:=xlWhole)
If Not f Is Nothing Then
'found the header, so create an array of the sheet names
Set rng = ws.Range(f.Offset(1, 0), ws.Cells(ws.Rows.Count, f.Column).End(xlUp))
arr = Application.transpose(rng.Value)
'use the array in the sheets Copy method
ThisWorkbook.Sheets(arr).Copy
Else
'alert if you tried to copy a non-existent group
MsgBox "Sheet group '" & GroupName & "' was not found!"
End If
End Sub

Related

If cell = value then copy and paste cell below with addition

I have a spreadsheet with values starting at A5 and running across to column AI, there could be any number of entries to the rows.
Row A contains an Item code (e.g. 000-0000)
I am looking to produce some code to complete the following two actions:
If column AI = yes, then copy entire row and paste below. With every copy add a sequential alphabetised letter to the code in column A (e.g. 000-0000a)
Any help would be greatly appreciated. Everything i've found expands to copying to another sheet and i'm struggling to break down the code.
Thanks
Edit:
Please see below current code I have been trying to get to work which works up to the point of copying the row however fails to paste it.
Sub NewItems(c As Range)
Dim objWorksheet As Worksheet
Dim rngNewItems As Range
Dim rngCell As Range
Dim strPasteToSheet As String
'Used for the new worksheet we are pasting into
Dim objNewSheet As Worksheet
Dim rngNextAvailbleRow As Range
'Define the worksheet with our data
Set objWorksheet = ThisWorkbook.Sheets("Sheet1")
'Dynamically define the range to the last cell.
'This doesn't include and error handling e.g. null cells
'If we are not starting in A1, then change as appropriate
Set rngNewItems = objWorksheet.Range("A5:A" & objWorksheet.Cells(Rows.Count, "A").End(xlUp).Row)
'Now loop through all the cells in the range
For Each rngCell In rngNewItems.Cells
objWorksheet.Select
If rngCell.Value <> "Yes" Then
'select the entire row
rngCell.EntireRow.Select
'copy the selection
Selection.Copy
'Now identify and select the new sheet to paste into
Set objNewSheet = ThisWorkbook.Sheets("Sheet1" & rngCell.Value)
objNewSheet.Select
'Looking at your initial question, I believe you are trying to find the next available row
Set rngNextAvailbleRow = objNewSheet.Range("A1:A" & objNewSheet.Cells(Rows.Count, "A").End(xlUp).Row)
Range("A" & rngNextAvailbleRow.Rows.Count + 1).Select
ActiveSheet.Paste
End If
Next rngCell
objWorksheet.Select
objWorksheet.Cells(1, 1).Select
'Can do some basic error handing here
'kill all objects
If IsObject(objWorksheet) Then Set objWorksheet = Nothing
If IsObject(rngBurnDown) Then Set rngNewItems = Nothing
If IsObject(rngCell) Then Set rngCell = Nothing
If IsObject(objNewSheet) Then Set objNewSheet = Nothing
If IsObject(rngNextAvailbleRow) Then Set rngNextAvailbleRow = Nothing
End Sub
So there are lots of things to address with your code. Many of which I have touched on. But the main thing to observe is that you are testing Column A not Column AI for the presence of "Yes" - so there may not be a match hence no copy.
As the paste destination is determined by a concatenation to create a sheet name you should have a test to ensure that sheet exists.
For testing I simply ensured a sheet called Sheet1a existed, that Sheet1 cell A5 had "a" in it, and there was a "Yes" in column AI. This could be improved but is enough to get you going.
This line is looping column A:
Set rngNewItems = objWorksheet.Range("A5:A" & lastRow)
Whereas this line is testing column AI:
If rngCell.Offset(, 35).Value <> "Yes"
Note <> means Not Equal as opposed to =
So perhaps you wanted:
If rngCell.Offset(, 35).Value = "Yes"
Consider the following re-write.
Option Explicit
Public Sub NewItems() 'c As Range) 'I have commented out parameter which isn't currently used.
Dim rngBurnDown As Range ' not used but also not declared
Dim objWorksheet As Worksheet
Dim rngNewItems As Range
Dim rngCell As Range
Dim strPasteToSheet As String
Dim objNewSheet As Worksheet
Dim lastRowTargetSheet As Long
Set objWorksheet = ThisWorkbook.Sheets("Sheet1")
Dim lastRow As Long
lastRow = objWorksheet.Cells(Rows.Count, "A").End(xlUp).Row
Set rngNewItems = objWorksheet.Range("A5:A" & lastRow)
Dim copiedRange As Range 'for union
For Each rngCell In rngNewItems.Cells
'Debug.Print rngCell.Address 'shows where looping
If rngCell.Offset(, 35).Value = "Yes" Then
Set objNewSheet = ThisWorkbook.Sheets("Sheet1" & rngCell.Value)
Dim nextTargetCell As Range
lastRowTargetSheet = objNewSheet.Cells(Rows.Count, "A").End(xlUp).Row
Set nextTargetCell = objNewSheet.Range("A" & lastRowTargetSheet)
rngCell.EntireRow.Copy nextTargetCell
Set objNewSheet = Nothing 'clear inside loop as you are setting in loop
lastRowTargetSheet = 0
Set nextTargetCell = Nothing
End If
Next rngCell
objWorksheet.Cells(1, 1).Select
End Sub
As for your lettering:
There are lots of examples online to generate these. Here is one way, by #harfang, from here:
Sub List_A_to_ZZZZ()
Dim i As Long
For i = 1 To 20 ' I have shortened this QHarr. Original end was 475254 ' ColXL("ZZZZ")
Debug.Print Right("---" & XLcL(i), 4)
Next i
End Sub
Function XLcL(ByVal N As Long) As String
Do While N > 0
XLcL = Chr(vbKeyA + (N - 1) Mod 26) & XLcL
N = (N - 1) \ 26
Loop
End Function
Function ColXL(ByVal abc As String) As Long
abc = Trim(Replace(UCase(abc), "-", ""))
Do While Len(abc)
ColXL = ColXL * 26 + (Asc(abc) - vbKeyA + 1)
abc = Mid(abc, 2)
Loop
End Function

VBA check criteria in 1 workbook, input values in another workbook

I am struggling to figure out how to get the code to do what I want, I wrote as much as I could with what I could find online, but for some aspects, I don't know what write.
Purpose of the code
Check "spreadsheet 2017" for the number "1" next to each name. If there is a "1", then enter values in multiple cells in a row in another workbook called "Dates template" (in the same row as name in "spreadsheet 2017")
Details on what I would like it to do
Column A and B has list first name (A), and surname (B)
Check through column C for "1", next to the names
If there is a 1, then switch to workbook "Dates Template"
find the same name in column A, and put the values 7.2 (col B), 3.9 (col C) and 74.2 (col D).
This is the basic backbone of the code, in the future I will be looking to add additional conditions, such as 1 in column D for example as well 1 in column C. so maybe a case function would work better, then it would be easier to add in the future. I don't know which is better.
In the code below I only wrote it to scan through the surnames in column B, because there are no duplicates. but in the future, it is likely that there will be names with the same surname, in which case first name will have to be read as well. This is where I'm confused on how to check both.
A bonus would be if its possible to copy the list of names over to the "Dates template" and then input those values if the criteria is met. Because at the moment I manually type up the names onto the "Date Template" Spreadsheet.
Sub Summary()
Dim wb1 As Workbook
Dim Sht As Worksheet
Dim Rng As Range
Dim wb2 As Workbook
Dim cell As Range
Dim ws As Worksheet
Set wb1 = Workbooks("Works template.xlsm")
Set wb2 = Workbooks("Spreadsheet 2017")
Set Sht = wb1.Worksheets("Template")
Set ws = wb2.Worksheets("January")
Set Rng = ws.Range("B7:B" & Sht.Cells(Sht.Rows.Count, "B").End(xlUp).Row)
For Each cell In Rng
If cell.Offset(0, 2).Value = "1" Then
Sht.Cells.Offset(0, 3).Value = "7.2" '<--- This is where I get the new error, "Application-defined or object-defined error"
Sht.Cells.Offset(0, 2).Value = "3.9"
Sht.Cells.Offset(0, 6).Value = "74.2"
End If
Next
End Sub
Thanks a lot!
Sht.Cells refers to all cells in the sheet, so you can't use .Offset() on this.
Sub Summary()
Dim wb1 As Workbook
Dim Sht As Worksheet
Dim Rng As Range
Dim wb2 As Workbook
Dim cell As Range
Dim ws As Worksheet
Set wb1 = Workbooks("Works template.xlsm")
Set wb2 = Workbooks("Spreadsheet 2017")
Set Sht = wb1.Worksheets("Template")
Set ws = wb2.Worksheets("January")
Set Rng = ws.Range("B7:B" & Sht.Cells(Sht.Rows.Count, "B").End(xlUp).Row)
For Each cell In Rng
If cell.Offset(0, 1).Value = "1" Then
sht.Range(cell.address).Offset(-2, 0).Offset(0, 0).Value = "7.2"
sht.Range(cell.address).Offset(-2, 0).Offset(0, 1).Value = "3.9"
sht.Range(cell.address).Offset(-2, 0).Offset(0, 2).Value = "74.2"
End If
Next
End Sub
Sub Insertdata()
Dim iAge As Integer
Set src = Workbooks.Open("age.xlsm", True, True)
t = 2
lastrow = ActiveSheet.UsedRange.Rows.Count
Do Until t = lastrow
iAge = src.Worksheets("Sheet1").Range("B" & t).Value
ThisWorkbook.Worksheets("Sheet1").Range("B" & t).Value = iAge
t = t + 1
Loop
End Sub
the same program how do we return not listing but connnected date with key
How do we remake the program to copy one value

VBA Excel Copy and Paste a table into a new Workbook and choice which Columns i want to copy

I want to copy a table into a new Workbook while choosing which range I want to copy and knowing that the first Columns ("A") is automatically copied. (rows are not a problem, all of them have to be copied)
For example, i have a table composed of 28 rows and 10 columns. Added to A1:A28 (first columns, all rows),i want just to copy the column 5 and 8 with all its rows.
That's what i have until now but it doesn't work.
Sub CommandButton1_Click()
Dim newWB As Workbook, currentWB As Workbook
Dim newS As Worksheet, currentS As Worksheet
Dim CurrCols As Variant
Dim rng As rang
'Copy the data you need
Set currentWB = ThisWorkbook
Set currentS = currentWB.Sheets("Feuil1")
'select which columns you want to copy
CurrCols = InputBox("Select which column you want to copy from table (up to 10)")
If Not IsNumeric(CurrCols) Then
MsgBox "Please select a valid Numeric value !", vbCritical
End
Else
CurrCols = CLng(CurrCols)
End If
'Set rng = currentWB.currentS.Range(Cells(1, A), Cells(27, CurrCols)).Select
currentS.Range("A1:A27").Select
Selection.copy
Set rng = currentWB.currentS.Range(Cells(1, CurrCols), Cells(28, CurrCols)).Select
rng.copy
'Create a new file that will receive the data
Set newWB = Workbooks.Add
With newWB
Set newS = newWB.Sheets("Feuil1")
newS.Range("A1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
End With
End Sub
Can you help please solving it? Thanks in advance!
You can't copy a non-continuous range but you can load the data into an array and write it once to the new workbook.
Private Sub CommandButton1_Click()
Dim arData
Dim MyColumns As Range, Column As Range
Dim x As Long, y As Long
On Error Resume Next
Set MyColumns = Application.InputBox(Prompt:="Hold down [Ctrl] and click the columns to copy", Title:="Copy Columns to new Workbook", Type:=8)
On Error GoTo 0
If MyColumns Is Nothing Then Exit Sub
Set MyColumns = Union(Columns("A"), MyColumns.EntireColumn)
Set MyColumns = Intersect(MyColumns, ActiveSheet.UsedRange)
ReDim arData(1 To MyColumns.Rows.Count, 1 To 1)
For Each Column In MyColumns.Columns
y = y + 1
If y > 1 Then ReDim Preserve arData(1 To MyColumns.Rows.Count, 1 To y)
For x = 1 To Column.Rows.Count
arData(x, y) = Column.Rows(x)
Next
Next
With Workbooks.Add().Worksheets(1)
.Range("A1").Resize(UBound(arData, 1), UBound(arData, 2)) = arData
.Columns.AutoFit
End With
End Sub
try this (commented) code
Option Explicit
Sub CommandButton1_Click()
Dim newSht As Worksheet
Dim currCols As String
Dim area As Range
Dim iArea As Long
Set newSht = Workbooks.add.Worksheets("Feuil1") '<--| add a new workbook and set its "Feuil1" worksheet as 'newSht'
currCols = Replace(Application.InputBox("Select which column you want to copy from table (up to 10)", "Copy Columns", "A,B,F", , , , , 2), " ", "") '<--| get columns list
With ThisWorkbook.Worksheets("Feuil1") '<--| reference worksheet "Feuil1" in the workbook this macro resides in
For Each area In Intersect(.Range(ColumnsAddress(currCols)), .Range("A1:G28")).Areas ' loop through referenced worksheet areas of the range obtained by crossing its listed columns with its range "A1:G28"
With area '<--| reference current area
newSht.Range("A1").Offset(, iArea).Resize(.Rows.Count, .Columns.Count).value = .value '<--| copy its values in 'newSht' current column offset from "A1" cell
iArea = iArea + .Columns.Count '<--| update current column offset from 'newSht' worksheet "A1" cell
End With
Next area
End With
End Sub
Function ColumnsAddress(strng As String) As String
Dim elem As Variant
For Each elem In Split(strng, ",")
ColumnsAddress = ColumnsAddress & elem & ":" & elem & ","
Next
ColumnsAddress = Left(ColumnsAddress, Len(ColumnsAddress) - 1)
End Function
I think you can copy all column to a temp sheet and then write some code to delete the useless column. finally paste the table to your expected area.

How to copy a range of cells and paste values to two different worksheets?

I have a range of data on Sheet2 that links it to Sheet1 (Sheet1 is formatted and linked by Sheet2 using =if(Sheet2$x$x="","",Sheet2$x$x); this way any data put into the range C13:G62 of Sheet2 shows up in Sheet1 range C13:G62. The beginning portion on the code works to move JUST the data in the specified range to the BATCH file Sheet3 and finds the last row pasting the values from Sheet1 without copying the formulas. It was made this way so I can delete data on Sheet2 to wipe Sheet1 clean but still have all the backup data on one Sheet3.
Anyway, the problem lies when I tried to manipulate the code to copy all contents on Sheet1 (to DUPLICATE SHEET1) to another sheet at the end of the workbook:
Sheets(Sheet1).Copy After:=Sheets(Sheets.Count)
ActiveSheet.Name = _
InputBox("Name of the New WorkSheet")
This allowed me to name the sheet which was great. However by creating multiple variations of code it will not move the DATA in the RANGE to the newly created Sheet4 (there is no data). In one iteration of code I was able to get Sheet1 to copy and make Sheet4 at the end of the work book with no data in the range but have the cursor land in cell C13, the starting point for pasting just the values, and when I left click the mouse in that cell to "paste values" it would paste the values that I was trying to paste. However, either way I rearranged the code, the data would always be copied but would never paste to the Sheet4 range.
Here I have posted one variation of the code IN WHICH IT STILL WILL NOT PASTE THE VALUES TO SHEET4 (THE NEWLY CREATED SHEET) but still copies to the BATCH FILE. What am I missing here?
Dim s1Sheet As Worksheet
Dim s2Sheet As Worksheet
Dim source As String
Dim target As String
Dim rngSource As Range
Dim rngTargetStart As Range
source = "Invoice"
target = "TOTAL_INVOICE"
Application.EnableCancelKey = xlDisabled
Set s1Sheet = Sheets(source)
Set s2Sheet = Sheets(target)
Set rngSource = s1Sheet.Range("C13:G62")
Set rngTargetStart = s2Sheet.Range("C" & Rows.Count).End(xlUp).Offset(1)
'Set rngTargetFinish = ws1.Range("C" & Rows.Count).End(xlUp).Offset(1)
rngTargetStart.Resize(rngSource.Rows.Count, rngSource.Columns.Count).Value = rngSource.Value
'rngTargetFinish.Resize(rngSource.Rows.Count, rngSource.Columns.Count).Value = rngSource.Value
'Set target = Sheets("Sheet4").Range("B13:G63")
copy_non_formulas source:=rngSource, target:=rngTargetStart
' copy_non_formulas source:=Range("B13:G63"), target:=Range("B70:G109") Unhighlight
' copy_non_formulas source:=Range("B13:G63"), target:=Range("B13:G63") Unhighlight
'===Copies Sheet to End of WorkBook & Pastes Values======
Sheets(source).Copy After:=Sheets(Sheets.Count)
ActiveSheet.Name = _
InputBox("Name of the New WorkSheet")
Range("C13:G62").ClearContents
Dim rng As Range
Set rng = ActiveSheet.Range("C13:G62")
rng.ClearContents
Dim s3Sheet As Worksheet
Dim rngTargetStart2 As Range
Set s3Sheet = Sheets(Sheets.Count)
Set rngTargetStart2 = s3Sheet.Range("C" & Rows.Count).End(xlUp).Offset(1)
rngTargetStart2.Resize(rngSource.Rows.Count, rngSource.Columns.Count).Value = rngSource.Value
copy_non_formulas2 source:=rngSource, target2:=rngTargetStart2
copy_non_formulas2 source:=Range("C13:G62"), target2:=Range("C13:G62")
This is an Integrated Public Sub
copy_non_formulas(source As Range, target As Range)
Dim i As Long
Dim j As Long
Dim c As Range
For i = 1 To source.Rows.Count
For j = 1 To source.Columns.Count
Set c = source(RowIndex:=i, ColumnIndex:=j)
If Left(c.Formula, 1) <> "=" Then
target(RowIndex:=i, ColumnIndex:=j).Value = c.Value
End If
Next j
Next i
And another Public Sub for the Second Move
copy_non_formulas2(source As Range, target2 As Range)
Dim x As Long
Dim y As Long
Dim d As Range
For x = 1 To source.Rows.Count
For y = 1 To source.Columns.Count
Set d = source(RowIndex:=x, ColumnIndex:=y)
If Left(d.Formula, 1) <> "=" Then
target2(RowIndex:=x, ColumnIndex:=y).Value = d.Value
End If
Next y
Next x

How to run a macro on some but not all sheets in a workbook?

I have a workbook that contains worksheets for each industry group in the S&P 500 and wrote the macro below to update all the stock information on them when I press a command button on the first worksheet. The macro works perfectly, but when I go to add additional sheets that I do not want to update with this macro it stops working. I tried using the "If Not" statements below, but it did not seem to work.
Sub Get_Stock_Quotes_from_Yahoo_Finance_API()
'Run the API for every sheet in the workbook
Dim Sht As Worksheet
For Each Sht In ThisWorkbook.Worksheets
'Look to see what the sheet is named and run the macro if it is not what is below
If Not Sht.Name = "Cover" _
And Not Sht.Name = "Select Industry" Then
Sht.Activate
' Dim varibales and set range
Dim head As Range
Set head = Worksheet.Range("A2")
'dim variables
Dim I As Integer
Dim Symbols As String: Symbols = ""
Dim SpecialTags As String: SpecialTags = ""
Dim Yahoo_Finance_URL As String: Yahoo_Finance_URL = "http://finance.yahoo.com/d/quotes.csv?s="
Dim rng As Range
Dim cell As Range
' Get the Stock Symbols
Set rng = Range(head.Offset(1, 0), head.Offset(1, 0).End(xlDown))
For Each cell In rng ' Starting from a cell below the head cell till the last filled cell
Symbols = Symbols & cell.Value & "+"
Next cell
Symbols = Left(Symbols, Len(Symbols) - 1) ' Remove the last '+'
' Get the Special Tags
Set rng = Range(head.Offset(0, 1), head.Offset(0, 1).End(xlToRight))
For Each cell In rng ' Starting from a cell to the right of the head cell till the last filled cell
SpecialTags = SpecialTags & cell.Value
Next
' Put the desciption/name of each tag in the cell above it
Dim SpecialTagsArr() As String: Dim TagNamesArr() As String
Call Get_Special_Tags(SpecialTagsArr, TagNamesArr)
For Each cell In rng
cell.Offset(-1, 0).Value = FindTagName(cell.Value, SpecialTagsArr, TagNamesArr)
Next
Yahoo_Finance_URL = Yahoo_Finance_URL & Symbols & "&f=" & SpecialTags
Call Print_CSV(Yahoo_Finance_URL, head)
Next Sht
'At the end of the program say it has all been updated
MsgBox ("All Data Updated")
End Sub
Change
If Not Sht.Name = "Cover" _
And Not Sht.Name = "Select Industry" Then
To
If Sht.Name <> "Cover" And Sht.Name <> "Select Industry" Then
Don't forget your End If before Next Sht
Refering to Kevin's second code - now the exclusion logic is flawed. I suggest the following:
Function IsIn(element, arr) As Boolean
IsIn = False
For Each x In arr
If element = x Then
IsIn = True
Exit Function
End If
Next x
End Function
Sub Get_Stock_Quotes_from_Yahoo_Finance_API()
Dim skippedSheets()
skippedSheets = Array("Cover,Select Industry,bla bla")
For Each Sh In ActiveWorkbook.Worksheets
If Not IsIn(Sh.Name, skippedSheets) Then
' ... process Sh
End If
Next Sh
End Sub
Now you have all sheet names which are to be excluded in one place (the array assignment) and the inner code block will only be executed if the current sheet name is not element of that array.
Second source of error: you already started qualifying the ranges (like in Set head = Sht.Range("A2")). Do the same in 2 other places, with
Set rng = Sht.Range(head.Offset(1, 0), head.Offset(1, 0).End(xlDown))
and
Set rng = Sht.Range(head.Offset(0, 1), head.Offset(0, 1).End(xlToRight))
Last, you don't have to activate a sheet. You work with the Sht object and qualified ranges.
Dim I as Integer is unused.