For loop not capturing all values in SAP - vba

new to SAP but have done some VBA programming.
I need to automate some things in SAP using Excel VBA but I am starting with baby steps and getting stumped.
All I want to do is copy data from a column in SAP (table already open) into an array. Sounds simple. However it starts off well, but never finishes properly. I have a table that has 306 rows. It has gotten stuck at 85, 127, and 178. Not sure if these values mean anything. What's even more puzzling to me is why does it return a value of 0000000127?? I've been looking for an answer for hours.
Running SAP Complex and Excel 2013. Cannot locate SAPfewse.ocx either. I've enabled almost all references in VBA Developer window. Any help/ideas would be much appreciated! I'm hoping it is something obvious.
Set Table = Session.FindById("wnd[0]/usr/cntlDISASSEMBLY_ALV/shellcont/shell")
Dim rows As Long
Dim arrRow() As Variant
Dim colName As String
Dim rowCount As Double
rows = Table.rowCount - 1
ReDim arrRow(rows)
colName = "ZZMRO_CHA"
For j = 0 To rows
arrRow(j) = Table.GetCellValue(j, colName)
Next
Array watch output - "completed" loop

You could try the following:
...
For j = 0 To rows
arrRow(j) = Table.GetCellValue(j, colName)
If j Mod 32 = 0 Then Table.currentCellRow = j
Next
...
Regards, ScriptMan

Related

How can I add values from table 1 to values in the cells of table 2 and display the result in table 2 after?

I am looking at somewhat of a problem when trying to program a macro in Excel that is meant to add the number values from 2 tables and display the updated total in the second of the two.
I have just started learning how to program macros, so my knowledge is a little basic, but I am sure that there has to be a way to set this up in a more convenient way than what I am doing right now.
I have two tables, table 1 contains the data of the current week, which is entered manually, while table 2 is supposed to contain the total, which is calculated when clicking the macro button "Add".
I was able to fully set this up myself, using very basic code, which is why I am asking for help. At the moment the macro code is very messy and absolutely massive, I am looking at 242 declared variable values and a total of 925 lines of code.
The below is simplified and shortened, but basically how everything is working right now:
Each table contains up to 11 columns of data, with 11 rows each, so the macro is adding cells B2 to L12 to cells B29 to L39. The results are then being displayed as the total in cells B29 to L39.
The code right now:
Sub Add()
Dim Add As Integer
Dim var1 As Integer
Dim var2 As Integer
var1 = Range("B2").Value
var12 = Range("B29").Value
Add = var1 + var12
Range("B29").Select
ActiveCell.FormulaR1C1 = Add
Like I said, this does work and does exactly what I need, but this involves a lot of code and a huge potential for mistakes, as well as hours of writing it all out. Doesn't look very good either, and is even harder to follow/work through.
Can anybody help me streamline this, make it shorter? Is there any option to sum the whole thing up in fewer lines of code, fewer arguments?
Thanks in advance for any help.
UPDATE:
As mentioned before, the code I currently have does work as intended, but I would like to cut it down volume wise. There's just too much of it and I know it is possible to do the exact same with a lot less, I just don't know how.
I have structured the code to make it a little easier to read, the first section declaring the variables, the next chunk declaring the values (separated into blocks per row in the table) and lastly the calculating action of adding table A to table B and displaying the result in table B (again, separated into blocks per row in the table).
Thank again everyone for your help.
This is the complete code currently written
Try this out:
Dim cell as Range
For each cell in Range("B29:L39")
cell.Value = cell + cell.offset(-27).Value
Next
you could use PasteSpecial() method with xlPasteSpecialOperationAdd value for its Operation parameter
Range("B2:L12").Copy
Range("B29:L39").PasteSpecial Operation:=xlPasteSpecialOperationAdd
Application.CutCopyMode = False
or you could use arrays
Dim i As Long, j As Long
Dim var1 As Variant, var2 As Variant
var1 = Range("B2:L12").Value
var2 = Range("B29:L39").Value
For i = 1 To UBound(var1, 1)
For j = 1 To UBound(var1, 2)
var2(i, j) = var2(i, j) + var1(i, j)
Next
Next
Range("B29:L39").Value = var2

Using variable sheetname in VBA

I'm a novice at VBA (just starting to learn). In my userform I have a combobox with values from 1 to 12(not string) representing the months. I want the user to pick a month and based on that, the multiple listboxes and labels I have placed should get filled by the relevant values in one of the 12 sheets representing each month. as I am a novice I have a lot of problems here but for starters the following lines do not seem to work on userform_initiate()
For j = 0 To 1
arr_trh(0, j) = Sheets("Sheet6").Cells(4, j + 1)
Next j
I can get it to work for a single sheet by using
arr_trh(0, j) = Sheet6.Cells(4, j + 1)
However, what I'm trying to do later on is to create a string and somehow concatenate "Sheet" and combobox value to pass on to Sheets() function.
Any help would be appreciated
Thanks
Rather than referring to the Sheet object like:
v = Sheet1.Range("A1")
use:
v = Sheets(1).Range("A1")
which you can index like:
v = Sheets(i).Range("A1")
where i is a variable.
I guess, my this answer will help you to figure out how to refer to sheets. Also, it tells about caveats of Index property.

Excel Summing over Rows with for loop - Type mismatch error

so I am currently working on an Excel sheet where I have to calculate confidence intervals. Long story short, I think the only way I can do this automatically, is to write vba code. The first step would be to calculate the average of the cells in a column for several columns in the sheet. What I did:
Dim temp As Double
temp = 0
Dim it_row As Long
for it_row = 1 to 100
if IsBlank(Sheet.Cells(it_row,it_col)) then
temp = temp + 0
else
temp = temp + Sheet.Cells(it_row,it_col).Value
end if
next it_row
Dim Average As Double
Average = temp/100
'writing average in another cell
This code does not work, as the compiler returns Type missmatch, error code 13
in the line
temp = temp + Sheet.Cells(it_row,it_col).Value
I tried to do a CDouble(Sheet.Cells(it_row,it_col).Value) but that did not work.
Any help is appreciated, as I am quite desperate because googling did not really help me.
I should mention that I do have to use vba and this code because this is part of a bigger automated process and my supervisor said I must use vba for automation in the next step.
The Average and Sum Excel Functions ignore text, boolean, and empty values:
Average = Application.Average(Sheet.Cells(1, it_col).Resize(100))
Check
Sheet.Cells(it_row,it_col).Value
...with
if isnumeric(Sheet.Cells(it_row,it_col).Value)
...before adding it to a double type value. If that check fails, then you can chose to skip it or treat it as sth. else.
I would've added this as a comment, but I don't have enough rep. to add comments.

How to use variables in regular MS excel expressions

My research shows that I need to use Visual Basic. I am a programmer/developer, but have never used VB so if anyone could dumb it down it would be appreciated.
Here's my working excel function:
=IF(MATCH(1,E1:DP1,0),D1,FALSE)
I want to loop a few of those numbers such that:
=IF(MATCH(141,E1:DP378,0),D378,FALSE)
THEN take my answers (which will be strings, because column D are all strings, the rest of the excel file are numbers)
=CONCAT
end goal: have 141 String arrays populated based on the data in my table.
I went ahead and made my first attempt at VBA like this:
Sub myFunc()
'Initialize Variables
Dim strings As Range, nums As Integer, answer() As Variant, listAnswers() As Variant
'set variables
strings = ("C1:C378")
nums = 141
i = 0
j = 0
ReDim Preserve answer(i)
ReDim Preserve listAnswers(j)
'answer() = {""}
'for each in nums
For counter = 0 To nums
ReDim Preserve listAnswers(0 To j)
'set each list of answers
listAnswers(i) = Join(answer(), "insertJSONcode")
j = j + 1
'for each in Stings
For Each cell In strings
If cell <> "" Then
ReDim Preserve answer(0 To i)
answer(i) = 'essentially this: (MATCH(2,E1:DP1,0),D1,FALSE)
i = i + 1
end If
next cell 'end embedded forEach
Next LCounter 'end for loop
'is this possible? or wrong syntax?
Range("A:A").Value = listAnswers() ' should print 141 arrays from A1 to A141
End Sub
EDIT:
Important note I do NOT need to call the sheet by Name. I've successfully written integer values to by excel sheet in column A without doing so.
Also, the VBA I wrote I was never intended to work, I know it's broken at least where answer(i) is supposed to write to something. I'm only putting that code there to show I was able to at least able to get into spitting distance of the proper logic and prove I've put some serious effort into solving the problem and give a rough starting point.
Here's an image of the excel format. Column C goes down to 378 and the numbers listed from E through DP are populated by a database. It consists of blank cells and numbers between 1 and 141.
Looking back at my if statement:
=IF(MATCH(2,E2:DP2,0),D2,FALSE)
If I were to type that exactly into cell B2 it would output the correct answer "text2". which is neat and all, but I need every instance of text 2 written out, then CONCAT those results. Easy so far, I could drag that down all the way through column B and have all of my "text" strings in one column, CONCAT that column and there's the answer. However I don't just need #2, I need each number between 1 and 141. Plus I want to avoid writing 141 columns with a CONCAT on top of each one.

Inspecting a Word mail merge data source programmatically

I want to iterate over all rows of a MS-Word mail merge data source and extract the relevant data into an XML.
I'm currently using this code:
Imports Microsoft.Office.Interop
Do
objXW.WriteStartElement("Recipient")
Dim objDataFields As Word.MailMergeDataFields = DataSource.DataFields
For Each FieldIndex As Integer In mdictMergeFields.Keys
strValue = objDataFields.Item(FieldIndex).Value
If Not String.IsNullOrEmpty(strValue) Then
strName = mdictMergeFields(FieldIndex)
objXW.WriteElementString(strName, strValue)
End If
Next
objXW.WriteEndElement()
If DataSource.ActiveRecord = LastRecord Then
Exit Do
Else
DataSource.ActiveRecord = Word.WdMailMergeActiveRecord.wdNextDataSourceRecord
End If
Loop
And it turns out to be a little sluggish (About 1 second for each row). Is there any way to do it faster?
My fantasy is finding a function like MailMergeDataSource.ToDatatable and then inspecting the datatable.
Any time you're iterating through something row by row, and then doing some kind of processing on each row, is going to get a little slow.
I would be inclined to approach this problem by having a step before this which prepared the mdictMergeFields collection so that it only contained elements that were not 'null or empty', this will mean you won't have to check for that on each iteration. You could do this in process, or 'sneakily' in the background while the user is doing something else.
The other thing to try (might help!) is to change the "Do... Loop" block so that you're not checking at the end of each imported row whether or the record is the 'last record'. Instead, get a count of the records, and then compare the current index to the knowm maximum (which might be quicker)
I.E.:
Dim i, x as Integer
i = ActiveDocument.MailMerge.DataSource.RecordCount
Do While x < i
objXW.WriteStartElement("Recipient")
Dim objDataFields As Word.MailMergeDataFields = DataSource.DataFields
For Each FieldIndex As Integer In mdictMergeFields.Keys
strValue = objDataFields.Item(FieldIndex).Value
If Not String.IsNullOrEmpty(strValue) Then
strName = mdictMergeFields(FieldIndex)
objXW.WriteElementString(strName, strValue)
End If
Next
objXW.WriteEndElement()
x += 1
Loop
I don't really work with the Office Interop much, but hopefully this might offer some assistance! Post back, let me know how it goes.
/Richard.