Replace customer ID with VBA variable in FindById() function? - excel

I am trying to automate some of my SAP work with VBA. I am stuck in the sign in as the script to customer price file is
session.FindById("wnd[1]/usr/cntlPRM_CC3000_1/shellcont/shell").SapEvent "Frame0", "sapbu_cl= &sapse_cl= &sapin_cl=S1F1E6~L&evtcode=ENTR&scroll_pos=0&S1F1E1L=2000&S1F1E2L=10&S1F1E3L=**98701**&S1F1E4L=&S1F1E4H=&S1F1E5L=&S1F1E5H=&S1F1E6L=12.10.2022", "sapevent:S1F1"
This is working well for the individual customer ID but I would like to loop through all the customers with different ID's specified in (Sheet 1, starting from A2). Therefore in this script I would need to use variable to replace the customer ID 98701. I found an instruction of using Cvar(Customer). However it leaves the Customer cell empty.
The code is below:
Dim i As Integer
Dim Customer As String
i = 2
Do Until IsEmpty(Cells(i, 1))
Customer = Range("A" & i)
On Error Resume Next
...
session.FindById("wnd[1]/usr/cntlPRM_CC3000_1/shellcont/shell").SapEvent "Frame0", _
"sapbu_cl= &sapse_cl= &sapin_cl=S1F1E6~L&evtcode=ENTR&scroll_pos=0&S1F1E1L=2000" _
& "&S1F1E2L=10&S1F1E3L=Cvar(Customer)&S1F1E4L=&S1F1E4H=" _
& "&S1F1E5L=&S1F1E5H=&S1F1E6L=12.10.2022", _
"sapevent:S1F1"
...
i = i + 1
Loop
Session.FindById(...) seems to be string and I cannot include variant as a value to it.
The cell has a field name as well to write or point out directly.
However I cannot find instructions on how to point to the certain field name directly in this case or include the variant to the Session.FindById string. Other solutions are welcome also!

You should use CStr instead and concatenate the strings correctly
session.FindById("wnd[1]/usr/cntlPRM_CC3000_1/shellcont/shell").SapEvent "Frame0", _
"sapbu_cl= &sapse_cl= &sapin_cl=S1F1E6~L&evtcode=ENTR&scroll_pos=0&S1F1E1L=2000" _
& "&S1F1E2L=10&S1F1E3L=" & CStr(Customer) & " S1F1E4L=&S1F1E4H=" _
& "&S1F1E5L=&S1F1E5H=&S1F1E6L=12.10.2022", _
"sapevent:S1F1"
Maybe the following links shed light on the topic string concatenation
How can I concatenate strings in VBA?
Concatenating strings containing " and & characters

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.

EXCEL VBA: For Loop involving checking Duplicates and continuing serial

I am new at using VBA and I am trying to do something that seems "simple." I have my VBA code generate a string (CP20210100001) and I want my for loop to check if that string has already been used in that column. If already used, generate the next in the serial until the next unique value in the serial has been generated.
My boss wants to paste a different ID occasionally in the column and this disturbs the code. My code looks at the last row and adds one to the String + serial. This will result in duplicates.
I figured out through much googling to get the code to check the current value for duplicates but I can't figure out how to get it to check for future IDs in the series until it comes across a unique value.
Below you can see my column. I had 10 successful submission and then my boss pasted 3 rows. With my VBA the next generated ID would be CP20210200004 but last part of the code found it as duplicate so it added 1 and inputted CP20210200005. Ideally the VBA should for loop until the next in the serial shows up. In this case CP20210200011. This way no matter how many times my boss disrupts my table, my ID sequence stays in tact.
**Reference ID**
CP20210100000
CP20210200001
CP20210200002
CP20210200003
CP20210200004
CP20210200005
CP20210200006
CP20210200007
CP20210200008
CP20210200009
CP20210200010
JS20210200001
JS20210200002
JS20210200003
CP20210200005
Below is the the VBA
#Timestamp is part of the String + Serial Combo
Timestamp = Format(Year(Date)) + Format(Month(Date), "00")
#I found this online. Essentially if A2 is blank then input CP + Timestamp + 00001 (CP20210100001)
#It looks at the last row to find the old value (OVAL) and generate the new value (NVAL)
If Sheets(ws_output).Range("A2") = "" Then
Sheets(ws_output).Range("A2").Value = "CP" & Timestamp + 1
Else
lstrow = Sheets(ws_output).Cells(Rows.Count, "A").End(xlUp).Row
Oval = Sheets(ws_output).Range("A" & lstrow)
NVAL = "CP" & Timestamp & Format(Right(Oval, 4) + 1, "00000")
#Here I am trying to see if NVAL is a duplicate value. If so add one to the serial.
Count = Application.WorksheetFunction.Countif(Sheets(ws_output).Range("A2:A100000"), NVAL)
Dim Cell As Range
For Each Cell In Sheets(ws_output).Range("A2:A100000")
If Count > 1 Then
NXVAL = NVAL
Else
NXVAL = "CP" & Timestamp & Format(Right(NVAL, 4) + 1, "00000")
End If
Next
Please please please help.
EDIT
I Should clarify that all of this is triggered on a form. The module is connected to a submit button. Once the button is pressed all the values in the form write to a separate sheet. Reference ID is the only part that isn't on the form. Essentially once the button is pressed, it triggers the query to write the next available reference ID. The next line in the query is
Sheets("Sheet2").Cells(next_row, 1).Value = NXVAL
I need the new Reference ID to equal a variable.
Your code seems to give you much grief and little comfort. The reason is that you didn't take a strictly logical approach. The tasks are ...
Find the last used number. I suggest to use VBA's own Find function.
Insert the next number. It consists of prefix, Date and serial number.
So, you arrive at code like this:-
Sub STO_66112119()
' 168
Const NumClm As Long = 1 ' 1 = column A
Dim Prefix As String
Dim LastNumber As Long
Dim Fnd As Range ' search result
Prefix = "JS" ' you could get this from an InputBox to
' enable numbering for other prefixes
With Columns(NumClm)
On Error Resume Next ' if column A is blank
Set Fnd = .Find(What:=Prefix, _
After:=.Cells(1, 1), _
LookIn:=xlValues, _
Lookat:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False)
End With
LastNumber = Val(Right(Fnd.Value, 5))
On Error GoTo 0
Cells(Rows.Count, NumClm).End(xlUp).Offset(1).Value = Prefix & Format(Date, "yyyymm") _
& Format(LastNumber + 1, "00000")
End Sub
You need to spend a moment on preparation, however.
Define the column to work in. I put this in the Const NumClm. It's at the top of the code so as to make maintenance easier (won't need to dig in the code to make a change).
My code shows Prefix = "JS". You want to change this to "CP". I inserted "JS" to show that you could use any prefix.
The above code will continue counting up in a new month and even a new year. If you want to start each year with a new series just change the way you handle the found previous. The Find function will return the cell where the prefix was last used. You might further examine that cell's value.

How to write a function that can combine two columns of indefinite length

I have a table in excel that has two columns, call them Tags and Note.
Tags can be empty cell or one tag, or many tags separated by a comma. (each tag is a string)
Note is just an arbitrary sentence (a note).
Note that a tag/tags do NOT reflect a specific note.
I would like to write a function that outputs a string that contains an ID (beginning with 0 for first row), the note and the tag/tags associated with that note.
My function must be able to work if I enter a new row/rows.
So far, I think i've managed to find a function that can read the end of my table. Now I need to be able to process Column A (Tags) to a specific format then concatenate my processed columns to a format similar to this:
{"id":0,"note":"contents of colB","tags":["tag1","tag2", etc]}
This is what I have :(
Sub Parse()
ActiveWorkbook.Sheets.Add.Name = "Result"
idindex = 0
For Each Line In Sheets("Template").Range("B2:B" &
Sheets("Template").Range("B2").End(xlDown).Row)
I'm not familiar with VBA but if I can figure out how to process the columns and append the id, i think I can figure out the formatting.
Might want to see this for good info on how to find the "last" row in a range/column/sheet/etc. Also a good practice to use Option Explicit which forces you to declare all variables (helps prevent typos, and other hard-to-trace errors that arise from implicit typing, etc.).
This is pretty basic string manipulation/string building. You'll need to use some of the built in VBA functions like Join, Split, etc., and you'll need to escape your quotation marks, so something like this:
Sub Parse()
Dim thisCell As Range
Dim id As Long
Dim columnRange As Range
Dim note As String
Dim tags As String
Dim output As String
ActiveWorkbook.Sheets.Add.Name = "Result"
id = 0
With Sheets("Template")
Set columnRange = .Range("B2:B" & .Range("B2").End(xlDown).Row)
For Each thisCell In columnRange
note = thisCell.Value
tags = thisCell.Offset(0, -1).Value
output = FormatOutput(id, note, tags)
' Remove the next line unless you want to print on the same worksheet in column C:
thisCell.Offset(0, 1).Value = output
' This line prints to the Result sheet:
Sheets("Result").Cells(id + 1, 1) = output
id = id + 1
Next
End With
End Sub
I made this fancy function to format the output based on the paramaters: id, thisNote (string) and theseTags (which we expect is the comma-delimited string of tags). I find it easier to build the parts like this when scripting, rather than trying to keep track of all my quotes and whether they're properly escaped/etc.:
Function FormatOutput(id As Long, thisNote As String, theseTags As String) As String
Const OPEN_ITEM As String = "{""id"":"
Const OPEN_NOTE As String = " ""note"":"
Const OPEN_TAGS As String = " ""tags"": ["
Const CLOSE_ITEM As String = "]}"
Const DBLQUOTE As String = """"
Const COMMA As String = ","
FormatOutput = OPEN_ITEM & CStr(id) & _
OPEN_NOTE & DBLQUOTE & thisNote & DBLQUOTE & COMMA & _
OPEN_TAGS & _
IIF(Len(Trim(theseTags)) = 0, "", _
DBLQUOTE & Join(Split(theseTags, COMMA), DBLQUOTE & COMMA & DBLQUOTE) & DBLQUOTE) & _
CLOSE_ITEM
End Function
And that gives me an output like:
{"id":0 "note":"this is a note", "tags": ["tag1","tag3","tag5"]}
It handles notes without tags and vice-versa:
That function (FormatOutput) is the brains behind this operation. It should (hopefully) be pretty straightforward, but this part is a little tricky if you're unfamiliar with the built-ins:
DBLQUOTE & Join(Split(theseTags, COMMA), DBLQUOTE & COMMA & DBLQUOTE) & DBLQUOTE
This ensures that we wrap each of our tag substrings in quotation marks for the output. The DBLQUOTE at the beginning puts a " before the first item, and likewise at the end puts a " after the last item.
Then we (Split(theseTags, COMMA)) split the delimited string on the commas, and Join them back with a new delimiter "," between each.
We need to do all of this tomfoolery because we're building a string that contains quotation marks, which are otherwise treated as either the beginning or end of a string.

Finding Partial Text In Full Row

I am trying to search an entire row for a string that contains "PROFILE". It will always be capitalized, but the format will be, for example "[9]PROFILE001".
Some extra information: I have used the Find command to locate the row that I am searching in for the string. It has its own variable that I am trying to incorporate into the range I am using.
I have searched multiple partial string articles on here, and have not been able to implement it into my code. I have tried using the Like command and the IntStr command to no avail. I believe my issue may be with how im referencing the search range or how i am searching.
Here is a snippet of my current code:
'finding item name row
Set FindRow3 = Range("A1:A100").Find("Item Name", LookIn:=xlValues)
itemnamerow = FindRow3.Row
'The section above is working as intended
'searching for the word profile, the section below is the one I am having issues with
Range("B8:Z100").Style = "Normal"
If ActiveSheet.Range("B" & itemnamerow & ":Z" & itemnamerow) Like "*PROFILE" Then
Range("C1").Value = "it worked"
End If
I am currently experiencing a run time error 13, type mismatch in the "If ActiveSheet..." line. I have not been able to get the correct index to make this correct.
I am trying to use that if the partial string is found, I want do something.
TIA
You need to use the Find method, with MatchCase and LookIn arguments set. And probably LookAt for to ensure it checks actual values and not formula syntax.
Dim profileFound as Range
Set profileFound = ActiveSheet.Range("B" & itemnamerow & ":Z" & itemnamerow).Find("PROFILE",lookIn:=xlValues,MatchCase:=True,lookAt:=xlPart)
If Not profileFound is nothing Then
debug.print profileFound.Value
Range("C1").Value = "it worked"
else
debug.print "no profile found"
End If
The reason your original code is failing is because Excel will not allow you to evaluate a multi-cell range against a single value. You could loop through each cell in the range and check each cell individually, but since Find is available, that is superfluous.
You don't provide enough parameters for the Range.Find operation. Switch to the worksheet's Match to locate Item name then again as a wildcard search to locate profile.
dim m as variant, n as variant
m = application.match("Item Name", range("A1:A100"), 0)
If not iserror(m) then
n = application.match("*profile*", cells(m, "B").resize(1, 25), 0)
If not iserror(n) then
Range("C1").Value = "it worked " & cells(m, n+1).value
end if
end if

Convert number in sci format to string in excel

I need to convert a column of alpha-numeric values to strings in an Excel function. CStr(value) works fine, UNLESS the value is something like 123E4. In that case, Excel treats the value as 1230000 and returns the string "1230000". Using Format(value,"#") yields the same result. The result I want is the string "123E4".
How can I get this?
The input cells are downloaded from a web site. They use the "General" format. I pass the value in a cell to the following function.
Function Var2Str(varA1 As Variant, Optional strFmt As String = "#") As String
Dim strTry As String
Dim strMsg As String
Debug.Print varA1, VarType(varA1), TypeName(varA1)
strTry = CStr(varA1)
Select Case VarType(varA1)
Case vbDouble
strTry = Format(varA1, strFmt)
Case vbString
'no further action
Case Else
strMsg = "Unhandled VarType in Var2Str" _
& vbCrLf & vbTab & "vara1 = " & varA1 _
& vbCrLf & vbTab & "varType = " _
& VarType(varA1) & vbCrLf & vbTab _
& "TypeName = " & TypeName(varA1)
MsgBox strMsg, vbOKOnly, "Information"
End Select
Var2Str = strTry
Debug.Print Var2Str
End Function
You could try (1) getting what you see in a string, and (2) using that to set the value of the target cell.
Sub test_format2()
Dim r As Range, r1 As Range
Set r = Selection
For Each r1 In r
Dim n1 As String
n1 = r1.Text ' (1)
r1.Offset(0, 1).Formula = "'" & n1 ' (2)
Next r1
End Sub
This seems to be the only bullet proof option.
For instance, 1.2e8 seems to be a challenging case when varying column width.
Variations on this question are common here. An oz of prevention is worth a pound of cure. So best to prevent the problem instead of trying to cure it after the fact:
In order to prevent Excel from converting certain alpha-numeric data that look like numbers or dates, into numbers or dates, you must IMPORT rather than OPEN the file. When you do that, the Text-import-wizard will open and you can designate the column as text before excel does the conversion.
Exactly how to do this depends on your version of Excel. In more recent versions, it will be on the Get & Transform tab on the Data Ribbon and may say something like From Text/CSV.
If you need to automate this, you can record a VBA macro while doing it.
I entered the values you listed above in a document using Notepad, and saved it as a csv file.
I then used the above method and got this result:
For me, the best solution was to use Workbook.OpenText to open the downloaded files and use the fieldinfo parameter to force the relevant columns to be formatted as text. The only trick is to make sure the downloaded file name has extension .txt, not.csv. For unknown reasons, VBA will not respect the fieldinfo parameter to open files with the .csv extension, regardless of the file content.

Resources