How to add several columns to a variable in Visual Basic (Excel) - excel

I have an issue of assigning several columns to a variable in Visual Basic. Is this possible at all?
Currently my code looks like this:
Do
Dim data As String
data = wsh.Cells(Row, 2) 'Data for barcodes is taken from this column
Now my question is: how can I assign/store more columns to a data variable? The method i tried below isn't permitted:
data= wsh.Cells(Row,2), wshCells(Row, 3), wshCells(Row, 4)
Basically, what I want to do is to take several columns that have some integer values. Out of these values, I want to generate QR Code and populate some specific columns with the generated QR code. With the current method that I have, I can only select one single column and populate another column. I can't select multiple columns and populate multiple columns respectively.
This is one the QR code is inserted into a specific column.
Set qrcode_cell = wsh.Cells(Row, 1) 'The cell where the QR Code will be placed
*Note i am using an excel add on tool called StrokeScribe.
Your help and suggestions are appreciated.

Transform your data variable into a list
dim datas() as string, pos as integer
pos = -1
' Add a column to datas
public sub addColumn(byval row as integer, byval col as integer)
pos = pos + 1
redim preserve datas(pos)
datas(pos) = wsh.Cells(row, col)
end sub
' Convert your datas into the format of your qrcode
public function retrieveData() as string
retrieveData = ""
dim data as string
for each data in datas
' data is the string you had in wsh.Cells(Row, col)
' do what you want with this column
next
' affect the result to "retrieveData" to retrieve datas in the needed format
end function

Just append each cell value to the existing string using &:
Do
Dim data As String
data = wsh.Cells(Row,2) & wsh.Cells(Row, 3) & wsh.Cells(Row, 4)
If you mean you want to add a value each time you loop then something like:
Do
Dim data As String
data = data & wsh.Cells(Row,2), wshCells(Row, 3), wshCells(Row, 4)
So you're just appending the cells onto the existing string.

Related

Concatenate values of more cells in a single variable in vba

I have an excel file with four columns: name, surname, address, area.
There are a lot of rows.
Is there a way to concatenate all the values of every single row in a variable, using vba?
I need a variable that should contain something like this:
(name1, surname1, address1, area1); (name2, surname2, address2, area2); (name3, surname3, address3, area3)...
If you have the following data in your worksheet
Then the following code will read the data into an array …
Option Explicit
Public Sub Example()
Dim RangeData() As Variant ' declare an array
RangeData = Range("A1:D5").Value2 ' read data into array
End Sub
… with the following structure:
Alternatively you can do something like
Public Sub Example()
Dim DataRange As Range
Set DataRange = Range("A2:D5")
Dim RetVal As String
Dim Row As Range
For Each Row In DataRange.Rows
RetVal = RetVal & "(" & Join(Application.Transpose(Application.Transpose(Row.Value2)), ",") & "); "
Next Row
Debug.Print RetVal
End Sub
To get this output:
(name1, surname1, address1, area1); (name2, surname2, address2, area2); (name3, surname3, address3, area3); (name4, surname4, address4, area4);
.. is there a way to write the result like a sort of list that shows all the values of the cells of the range?
Yes, there is. In addition to PEH's valid answers and disposing of Excel version MS365 you might also use
Dim s as String
s = Evaluate("ArrayToText(A2:D5, 1)") ' arg. value 1 representing strict format
resulting in the following output string:
{"name1","surname1","address1","area1";"name2","surname2","address2","area2";"name3","surname3","address3","area3";"name4","surname4","address4","area4"}
Syntax
ARRAYTOTEXT(array, [format])
The ARRAYTOTEXT function returns an array of text values from any specified range. It passes text values unchanged, and converts non-text values to text.
The format argument has two values, 0 (concise default format) and 1 (strict format to be used here to distinguish different rows, too):
Strict format, i.e. value 1 includes escape characters and row delimiters. Generates a string that can be parsed when entered into the formula bar. Encapsulates returned strings in quotes except for Booleans, Numbers and Errors.
Thank you for your answers, suggestions, ideas and hints. I am sorry if my question was not so clear, all the solutions you added were perfect and extremely elegant.
In the end I found a way - a dumber way in comparison to all the things you wrote - and I solved with a for statement.
I did like this:
totRow = ActiveSheet.UsedRange.Rows.Count
For i = 1 To totRow
name = Cells(i, 1)
surname = Cells(i, 2)
address = Cells(i, 3)
area = Cells(i, 4)
Example = Example & "(" & name & ", " & surname & ", " & address & ", " & area & "); "
Next i
Range("E1").Value = Example
It works (it does what I wanted to do), but I noticed a little limit: if the rows are a lot I can't keep the whole text in the variable.

Dynamic Lookup for multiple values in a cell (comma separated) and return the corresponding ID to a single cell (comma separated also)

The thing is not always the amount of values (IDs) will be the same within each cell (at least 1, max=several) that's why the fixed version of using concatenated vlookup+left/mid/right will not work for me due to that will solution will only work up to 3 values. The only fixed size is the size of the values to lookup (IDs - in green), 8 characters (letters+numbers).
I'm not sure but, is it possible to setup a loop within excel formulas/functions ?
Below is a table containing an example of the issue I'm trying to resolve and the expected values (tables are in different tab). Hope you can help.
Thanks.
example-tables
If you have windows Excel O365 with the TEXTJOIN and FILTERXML functions, you can use a formula:
=TEXTJOIN(",",TRUE,IFERROR(XLOOKUP(FILTERXML("<t><s>" & SUBSTITUTE(#[IDs],",","</s><s>") & "</s></t>","//s"),Table2[IDs],Table2[IDv2]),"""--"""))
Note that, in your data, there are two ID's in A4 that do not match any ID's in Table 2. Although that may be a typo, I left them as is to demonstrate the error handling.
Table1
Table2
Here is a UDF that will do what you describe. Paste the code into a standard code module (not one already existing in the workbook but one that you create and that would have a name like Module1 before you change it to what you like best. You can also rename the function to give it a more suitable name.
Function ID_v2(Cell As Range) As String
' 035
Dim Fun As String ' function return value
Dim Sp() As String ' array of CSVs of CellVal
Dim VLRng As Range ' the lookup range
Dim VL As Variant ' result of VLookup
Dim i As Integer ' loop counter
' this is a range similar to your sample A10:D19
Set VLRng = ThisWorkbook.Names("Table2").RefersToRange
Sp = Split(Cell.Cells(1).Value, ",")
If UBound(Sp) >= 0 Then
For i = 0 To UBound(Sp)
On Error Resume Next
VL = Application.VLookup(Trim(Sp(i)), VLRng, 3, False)
If Err Then VL = "[ERROR]"
Fun = Fun & VL & ","
Next i
ID_v2 = Left(Fun, Len(Fun) - 1) ' remove final comma
End If
End Function
Call the function with syntax like built-in functions. For example,
= ID_v2(A3)
This can be copied down like any other function. But remember to save the workbook as macro-enabled.
Try this:
Option Explicit
Sub Cell2List()
Dim wF As WorksheetFunction: Set wF = Application.WorksheetFunction 'To user Transpose
Dim i As Range
Dim j As Range
Dim s As String: s = "," 'The separator of the list
'Ask the user for the cell where are the list with the commas
'Just need to select the cell
Set i = Application.InputBox("Select just one cell where the values are", "01. Selecte the values", , , , , , 8)
'Ask the for the separator. If you are completely sure the comma will never change just delete this line
s = Application.InputBox("Tell me, what is the character separator, just one character! (optional)", "02. Separator (comma semicolon colon or any other char)", , , , , , 2)
If s = "" Then s = "," 'Verifying...........
'Ask the user where want to put the list
'You need to get ready the cells to receive the list.
'If there any data will be lost, the macro will overwrite anything in the cells
Set j = Application.InputBox("Select just one cell where the values will go as a list, just one cell!", "03. Selecte the cell", , , , , , 8)
Dim myArr: myArr = (Split(i.Value, s)) 'Split the list into a Array
Range(Cells(j.Row, j.Column), Cells(j.Row + UBound(myArr), j.Column)).Value = wF.Transpose(myArr)
'j.Row is the row of the cell the user selected to put the cell
'j.Column the same, but the column
'j.Row + UBound(myArr) = UBound(myArr) is the total count of elements in the list
' +j.Row
' _______________
' the last cell of the new list!
'wF.Transpose(myArr) = we need to "flip" the array... Don't worry, but Don't change it!
End Sub
You can put this macro with a button tin the ribbons, or use it as you can see in the gif
And this will be the result: (with a bigger list)
EDIT
You can use this UDF:
Function Cells2List(List As Range, Pos As Integer) As String
Cells2List = Split(List, ",")(Pos - 1)
End Function
Just need to define and index this way:
To tell the function, what index you want to see. You can use the function using ROW()-# to define an 1 at the beginning and when the formula send a #VALUE! delete the formulas. Where $A$1 is where the list are, and D7 is where the index are.

Return multiple rows of data in vba

I have a row such as the following:
Destination: Part:
04586 06509269AA
I want to look up this data in another sheet that has multiple rows of the same data with extra information
Destination: Part: Package:
04586 06509269AA 656665
04586 06509269AA 213226
and return the full data to a new sheet.
I tried doing an index, match, using a key for the data set but it crashes excel due to how much rows of data I actually pull in my query, and also I would need to find a way to increment rows in the new sheet for how many rows of data there actually is.
Any ideas of what I can try in VBA to create this report?
If I am understanding you are trying to get all the "Package values" based on "Part" and "Parameter". I would run a while loop with a for loop inside that iterates at a match and stores in an array that gets bigger using reDim Preserve.
example input with output pasted onto G column
Sub example()
Dim rower, destination, packageCount As Integer
Dim Package() As Variant
Dim part As String
destination = 4586
part = "06509269AA"
rower = 0
packageCount = 0
Sheets("Sheet1").Activate
Range("B3").Activate
Do While ActiveCell.Offset(rower) <> ""
If ActiveCell.Offset(rower) = destination And ActiveCell.Offset(rower, 1) = part Then
packageCount = packageCount + 1
ReDim Preserve Package(packageCount + 1)
Package(packageCount) = ActiveCell.Offset(rower, 2)
End If
rower = rower + 1
Loop
Range("g2").Activate
For i = 0 To UBound(Package)
ActiveCell.Offset(i) = Package(i)
Next i
End Sub

Excel VBA macro for extracting column numbers from plots

I often make a lot of scatter plots (column j vs column i) in a single Worksheet. I want to export them as png/jpg files. Each plot would need a sensible file name. I have thought that the file name could be something like plot_[column i]_[column j].png.
How do I get the column (like C or AE) from each plot (or ActiveChart)? Then I can create a file name string to be fed in to the Export method. I am a complete beginner for VBA macros, but understand some Visual Basic.
You can extract that information from the source data string using text functions. The source data is available using .SeriesCollection:
activesheet.chartobjects("Chart 1").chart.SeriesCollection(1).Formula
will return something like this:
"=SERIES(,Sheet1!$A$1:$A$4,Sheet1!$B$1:$B$4,1)"
That contains the two columns you need, "A" and "B". You can extract them using text functions like INSTR(), MID(), and LEFT(). Here is an example using debug.print to output the columns. I'm assuming you already know how to export them since that was not included in your question.
Sub FindSourceColumns()
Dim sourcedata, firstcolumn, secondcolumn As String, c as chartobject
for each c in activesheet.chartobjects
sourcedata = c.Chart.SeriesCollection(1).Formula
firstcolumn = Mid(sourcedata, InStr(sourcedata, "!$") + 2, 5)
firstcolumn = Left(firstcolumn, InStr(firstcolumn, "$") - 1)
Debug.Print firstcolumn
secondcolumn = Mid(sourcedata, InStr(InStr(sourcedata, "!$") + 2, sourcedata, "!$") + 2, 5)
secondcolumn = Left(secondcolumn, InStr(secondcolumn, "$") - 1)
Debug.Print secondcolumn
next c
End Sub

VBA: Loop through criteria in an Excel filter?

I've been trying to figure this out all morning. Is there a way to loop through the criteria in a column filter in Excel, while filling an array with the names of the criteria? It seems that filter objects only have a criteria1 and criteria2. Sorry if any of my terminology is unclear, I'm pretty new to Excel.
(this is using Excel 2007)
It appears that if you have 1 or 2 criteria selected then these will be stored in .Criteria1 and .Criteria2.
However if you have more than 2 then .Criteria1 becomes an array of the selected filters - which you can then iterate through using...
Dim iFilt As Integer 'This should be set equal to the column
'index you are interested in
Dim iFiltCrit as Integer
For iFiltCrit = 1 To UBound( Sheet1.AutoFilter.Filters(iFilt).Criteria1 )
Debug.Print Sheet1.AutoFilter.Filters(iFilt).Criteria1(iFiltCrit)
Next
Note that this only works for a column which has more than 2 criteria - how you determine if that is the case or not is up to you - it's a rather clunky piece of Excel API (surprise surprise) as it is loosely typed.
I had the same problem, where I wanted to have a user-defined string for filtering, in which people can give the column and the filtervalue for multiple columns at once.
In this example the string users can define looks like:
"A,foo;B,bar;AD,beyond all recognition"
Or
"ColumnLetterOrIndex comma FilterValue Semicolon" Repeat.
and so on for any number of columns and values.
Code:
Public Function createFilter(filterstring as string) as Variant
Dim tempFilter As Variant
Dim realFilter As Variant
tempfilter = Split(filterstring, ";")
For i = LBound(tempfilter) To UBound(tempfilter)
ReDim Preserve realFilter(i)
realFilter(i) = Split(tempfilter(i), ",", 2)
'The 2 is needed if the filtervalue contains a comma on itself. Otherwise, it can be omitted.
Next i
createFilter = realFilter
End Function
The above function will create a multidimensional array from a string of which the values can be used with Excels autofilter from a string. Usage code:
Dim userFilter as Variant
userFilter = createFilter(userDefinedFilterString)
For i = LBound(userFilter) To UBound(userFilter)
'Note that here you'll have to convert the Columnletter to something numeral, unless the users define their column like 1, 2, 3 instead of A, B, C.
thefiltercolumn = Measure.filter(i)(0)
.AutoFilter thefiltercolumn, Measure.filter(i)(1)
Next i
When the filtervalues are equal to the "Is not equal to" or "contains", you can use excel's built-in way of doing that, e.g.
A,<>foo;B,*bar*;AD,>=5
Bad part: Multiple criteria on 1 column is not available like in the previous example.

Resources