PDA

Vollständige Version anzeigen : SAP-Tabelle mit VBA auslesen und Werte exportieren


leMoi66
25.08.2017, 19:55
Hallo zusammen,

es gibt zwar schon ein paar Themen hier dazu, allerdings finde ich keines, welches mir hier weiterhilft...

es geht um Folgendes:
Ich habe ein Excel Template, welches in SAP CO eingebettet ist.
Mittels dieses Templates kann ich Plankostenrechnungen für bestimmte Projekte mit unterschiedlichen Stundensätzen automatisch berechnen lassen.

Nun ist es so, dass sich die Stundensätze alle 3-6 Monate ändern. Diese Änderungen werden in einer SAP-Tabelle hinterlegt. Das heißt, dass ich die Stundensätze in meinem VBA Code nicht "hard" coden kann. Besser ist es also,bevor die Plankostenrechnung durchgeführt wird, jene SAP-Tabelle mittels meines VBA Codes ausgelesen wird. Die jeweilige Plankostenberechnung soll sodann mit den aus der SAP-Kostentabelle ausgelesenen Stundensätzen durchgeführt werden.
Zum Auslesen von SAP-Tabellen stellt SAP BAPI-Funktionsbausteine zur Verfügung. Die hierfür benötigte BAPI lautet: BAPI_CTR_GETACTIVITYPRICES.

Nun habe ich den VBA Code zum SAP-Tabellen-Auslesen geschrieben:
Die SAP-Tabelle soll ausgelesen werden und in ein separates Excel-Tabellenblatt eingefügt werden, woraus sie den jeweiligen Berechnungsvariablen zugeordnet werden.

Mein Problem momentan ist, dass wenn ich über die Konsole ausgeben lasse, wie viele Zeilen die ausgelesen Tabelle hat, "0" angezeigt. Wenn ich über die Konsole ausgeben lasse, wie viele Spalten die SAP-Tabelle hat, erscheint "14". Was mit dem übereinstimmt, was in der SAP Doku dokumentiert ist. Meines Erachtens wird hier schon erkannt, dass es diese SAP-Tabelle gibt, allerdings wird sie nicht ausgelesen.

Sieht jemand zufällig meinen Fehler? Kann mir dann zufällig jemand helfen?
Das wäre meega!

Vielen Dank schon einmal im Voraus!

Und nun der Code:


Function GetActivityPrices()
'
'Declaration
'
Dim Destination_System As Integer
Dim objBAPIControl As Object 'Function Control (Collective object)
Dim sapConnection As Object 'Connection object
Dim ws As Worksheet 'Tarife

'separates Excel-Tabellenblatt, in welches die SAP Tabelle exportiert werden soll
Set ws = Excel.Worksheets("Tarife")

'Verbindung mit SAP vorbereiten
'
Set objBAPIControl = CreateObject("SAP.Functions")
Set sapConnection = objBAPIControl.Connection

'Prüft ob Connection erfolgreich --> gewünschtes SAP System kann hier manuell ausgewählt werden
'
If sapConnection.Logon(1, False) <> True Then
MsgBox "No connection to R/3!"
Exit Function 'End program
'
Else
MsgBox "Connection succeeded!"
End If

Set objTarifList = objBAPIControl.Add("BAPI_CTR_GETACTIVITYPRICES")

'Vorbereitung des Exports nach Excel --> hier werden im separaten Excel-Tabellenblatt die Spalten benannt
'
ws.Cells.Clear
ws.Range("A1:N1").Font.Bold = True
ws.Cells(1, 1) = "Kostenstelle"
ws.Cells(1, 2) = "Leistungsart"
ws.Cells(1, 3) = "Periode"
ws.Cells(1, 4) = "Tarifkennzeichen"
ws.Cells(1, 5) = "Tarif fix Curr"
ws.Cells(1, 6) = "Tarif variabel Curr"
ws.Cells(1, 7) = "Tarifeinheit Curr"
ws.Cells(1, 8) = "Währungsschlüssel"
ws.Cells(1, 9) = "Währungsschlüssel (ISO)"
ws.Cells(1, 10) = "Tarif fix Objekt-Curr"
ws.Cells(1, 11) = "Tarif variabel Objekt-Curr"
ws.Cells(1, 12) = "Tarifeinheit Curr"
ws.Cells(1, 13) = "Währungsschlüssel Objekt"
ws.Cells(1, 14) = "Währungsschlüssel Objekt (ISO)"


'Definiert die Import-Parameter für BAPI_CTR_GETACTIVITYPRICES
'
objTarifList.exports("COAREA") = "1000"
objTarifList.exports("FISCYEAR") = "2016" 'Jahr
objTarifList.exports("VERSION") = "0"
objTarifList.exports("COSTCENTERFROM") = "11110"
objTarifList.exports("COSTCENTERTO") = ""
objTarifList.exports("COSTCENTERGRP") = ""
objTarifList.exports("ACTTYPEFROM") = "110"
objTarifList.exports("ACTTYPETO") = ""
objTarifList.exports("PERIODFROM") = "8" 'AktuellerMonat
objTarifList.exports("PERIODTO") = "8" 'AktuellerMonat

'Aufruf der BAPI um Liste mit Tarifen zu erhalten
'
returnFunc = objTarifList.Call
Dim objTable As Object
Set objTable = objTarifList.Tables("ACTPRICES")
Debug.Print "Tarife: " & objTable.RowCount 'gibt aktuell 0 aus

If returnFunc = True Then

For i = 1 To objTable.RowCount

'Zeilenfarben für bessere Übersicht beim Lesen
'
If i Mod 2 = 0 Then
For j = 1 To objTable.ColumnCount
ws.Cells(i, j).Interior.Color = RGB(165, 162, 165)
Next j
Else
For j = 1 To objTable.ColumnCount
ws.Cells(i + i, j).Interior.Color = RGB(214, 211, 206)
Next j
End If

For x = 1 To objTable.ColumnCount
ws.Cells(i + 1, x) = objTable.cell(i, x)
Next x

Next i

Else
MsgBox "Error when accessing BAPI_CTR_GETACTIVITYPRICES"
Exit Function

End If

' Schließe Verbindung to R/3 !
'
objBAPIControl.Connection.Logoff
'
' Speicherzuordnung löschen
'
Set sapConnection = Nothing
Set functionCtrl = Nothing

If objTable.RowCount = 0 Then
MsgBox "Es wurden keine Tarife gefunden."
ElseIf objTable.RowCount = 1 Then
MsgBox "Es wurde " & objTable.RowCount & " Tarif gefunden."
Else
MsgBox "Es wurden " & " Tarife gefunden."
End If

End Function

Hajo_Zi
26.08.2017, 05:48
<a href="http://hajo-excel.de/crossposting.htm" title="Crossposting" >Zu Crossposting lies diese Seite Hajo-Excel.de</a>
Du hast Glück das JINX nicht mehr da ist, ansonsten würde Dein Beitrag wegen Crossposting geschlossen werden.
Ein Zitat aus der Netiquette (hier im Forum):
Unerwünscht sind auch Crosspostings - also dieselbe Frage gleichzeitig in mehreren Foren (nicht nur im MSOF).
Denn auf diese Weise werden mehrere Gruppen von Leuten mit dem gleichen Thema befasst, ohne dass sie voneinander wissen.
Naturgemäß laufen dann die Antworten, die im einen Forum "zu spät" gegeben wurden, ins Leere und bleiben ohne Resonanz.
Es reicht also, zunächst in einem Forum zu posten - wenn die Antworten dann unbefriedigend sein sollten, steht es einem anschließend immer noch offen, ein anderes Forum zu Rate zu ziehen.
Ich mache keine Werbung für andere Foren und verzichte darum auf den Link.
Die Forumssoftware verhindert das auch bei den meisten Foren.
<img src="http://Hajo-Excel.de/images/grusz1.gif" align="middle" height="40" alt="Grußformel"><a href="http://Hajo-Excel.de/index.htm"><img border="0" src="http://Hajo-Excel.de/images/logo_hajo3.gif" align="middle" height="40" alt="Homepage"></a>

WS-53
26.08.2017, 11:47
Hallo,

generell für das Auslesen von SAP-Tabellen aus Excel oder auch per RFC (Remote Function Call) avon einem anderem System, gibt es den Funktionsbaustein RFC_READ_TABLE.

Dazu habe ich auch funktionierendes Beispiel gefunden.

www.*************************125374_0_0_asc.php - Link funktioniert nicht!

Die Sterne müssen durch: Office - loesung . de ohne Leerzeichen ersetzt werden.


Dim FUBAU_rfc_read_table As Object
Dim functionCtrl As Object
Dim T_I_Options As Object
Dim T_I_Fields As Object
Dim T_E_Data As Object

Dim i, x As Integer
Dim strDataRow As String
Dim DataRow As Variant
Dim Col As Boolean
Col = False

Set functionCtrl = CreateObject("SAP.Functions")

Set FUBAU_rfc_read_table = functionCtrl.Add("RFC_READ_TABLE")
With FUBAU_rfc_read_table
.exports("QUERY_TABLE") = InputBox("Bitte Tabellenname eingeben")
.exports("DELIMITER") = "|" 'Delimiter
End With

Set T_I_Options = FUBAU_rfc_read_table.tables("OPTIONS")
Set T_I_Fields = FUBAU_rfc_read_table.tables("FIELDS")
Set T_E_Data = FUBAU_rfc_read_table.tables("DATA")

'Aufruf des FUBAs
ret = FUBAU_rfc_read_table.call

'Übetragen der Daten in Excel-Tabelle (z.B. immer in Tabelle1)
If T_E_Data.RowCount > 0 And ret = True Then

For i = 1 To T_E_Data.RowCount
strDataRow = T_E_Data(i, 1)
DataRow = Split(strDataRow, "|")

'Spaltenüberschriften an Excel übergeben
If Col = False Then
For x = 0 To UBound(DataRow)
' Tabelle1.Cells(1, x + 1).Value = T_I_Fields(x + 1, 1)
Sheet1.Cells(1, x + 1).Value = T_I_Fields(x + 1, 1)
Next x
Col = True
End If

For x = 0 To UBound(DataRow)
Sheet1.Cells(i + 1, x + 1).Value = DataRow(x)
Next x
Next i
End If

End Sub

Beim testen bin ich auf folgende Probleme gestoßen.

Die Breite aller Felder darf den Wert von 512 nicht übersteigen.

Bei Charakterfeldern, die einen numerischen Inhalt haben, werden die führenden Nullen abgeschnitten, da Excel diese in Zahlen umwandelt.

Somit wird aus Mandant 001 und Buchungskreis 0001 jeweils nur eine 1.

Wie sich dieses Problem beheben lässt, dazu habe ich im Moment keine Idee
(Per Makro nach dem Import nacharbeiten, kann eine Workaround sein).

Grundsätzlich kann dem Funktionsbaustein beim Aufruf wohl auch mitgebeben werden, welche Felder überhaupt geleifert werden sollen und auch die Selektionsoptionen können mitgegeben werden.

Bisher habe ich aber noch keine Idee, wie ich die Übergabestrukturen füllen muss.

Der Import einer Tabelle mit 27.000 Datensätzen hat bei mir etwa 1 Minute gedauert.

Wenn du beim Ersten Mal, das ausgewählte SAP-System als Default einstellst, musst du es nicht jedes Mal auswählen, aber bei Bedarf immer ändern.

Scorefun
26.08.2017, 12:41
Wenn der Aufruf des BAPI generell funktioniert, aber keine Ergebnisse liefert,
dann stimmt was nicht mit den Abfrage-Kriterien.

Eine Vermutung wäre:
Die Monate sind als Text in SAP zweistellig.
Versuch mal "08" statt "8"

Ich kenne solche Probleme beim Auslesen von Aufträgen
Ein Auftrag mit der Nummer 123456 muss man mit "0000123456" (10-stellig) übergeben

leMoi66
06.09.2017, 19:40
Hi Scorefun,

danke für deine Rückmeldung,

das ist in der Tat ein guter Hinweis - bisher noch nicht beachtet.

Ich habe das nun versucht bei allen Eingaben in SAP durchzuführen. Vorher habe ich nach den von SAP definierten Feldlängen der Import-Eingaben gesucht. Hier wurde für die Periode '3'Stellen definiert.
Als ich versucht habe '008' einzugeben, hat mein VBA Editor daraus automatisch '8' geschrieben.

Hast du oder ihr eine Idee, wie man das umgehen bzw. unterlassen kann?

Scorefun
06.09.2017, 20:29
Als ich versucht habe '008' einzugeben, hat mein VBA Editor daraus automatisch '8' geschrieben.


Wenn Du die 008 in Gänsefüsschen setzt, glaube ich nicht, daß da 'ne 8 draus wird

edit:
Oder gehst Du über eine Variable, die Du aus einer Excel-Zelle holst? Dann muss diese als String deklariert und entsprechend aufbereitet werden

Dim sMonat as string
sMonat = Range("A1") 'z.B. die 8

do while Len(sMonat) <3
sMonat = "0" & sMonat
loop

dann steht in der Variablen sMonat auf jeden Fall 008 als String, der dann dem SAP-Aufruf übergeben werden kann


objTarifList.exports("PERIODFROM") = sMonat 'AktuellerMonat
objTarifList.exports("PERIODTO") = sMonat 'AktuellerMonat


Dürfte das Problem von WS-53 auch lösen ;-)

WS-53
07.09.2017, 07:27
Hallo Ralf,

was die Abfrage angeht da hast du mit deinen Hinweisen Recht. In den SAP-Eingabemasken muss dies nicht beachtet werden, weil da die Konvertierungsregeln automatisch ablaufen.

Das von mir geschilderte Problem betrifft aber die empfangenen Daten, die von Excel automatisch konvertiert werden. Wenn dabei dann aus der Periode 008 eine 8 wird, ist dies kein Problem, aber wenn die Postleitzahl 01234, nach dem Import als Zahl mit 1234 dargestellt wird, dann ist es halt falsch.

Storax
07.09.2017, 07:56
betrifft aber die empfangenen Daten, die von Excel automatisch konvertiert werdenDamit hast Du die Ursache doch schon beschrieben. Excel konvertiert!!!

Scorefun
07.09.2017, 08:15
Das von mir geschilderte Problem betrifft aber die empfangenen Daten, die von Excel automatisch konvertiert werden.

Sehe ich genauso wie Storax - für die korrekte Verarbeitung und Darstellung der empfangenen Daten in Deiner Anwendung solltest Du sorgen, und dies nicht Excel überlassen ;)

Ein Hochkomma vor vermeintliche Zahlen wirkt da schon Wunder

'001

leMoi66
11.09.2017, 13:45
das habe ich versucht. Ebenso habe ich geprüft, ob die Feldlängen auch tatsächlich mit denen übereinstimmen, die SAP definiert hat. Trotzdem erscheint bei der Abfrage von "RowCount" der Wert "0" (null).

- die SAP Verbindung klappt
- die Rechte für den Zugriff sind vorhanden
- die erforderlichen Parameter gebe ich mit
- bei Abfrage der der Spaltenanzahl erscheint die 14, bedeutet die Tabelle wurde erkannt
- wenn ich die SAP Tabelle manuell abfragen, erscheinen auch die erforderlichen Daten

Habt ihr sonst eine Idee, was ich nicht beachtet haben könnte?


Vielen Dank schon einmal !!

BEste Grüße
leMoi66

Storax
11.09.2017, 14:17
Mein Tipp, debuggen, und zwar wie folgt
returnFunc = objTarifList.Call
Dim objTable As Object
Set objTable = objTarifList.Tables("RETURN")
Set objTable = objTarifList.Tables("ACTPRICES")
Bei Set objTable = objTarifList.Tables("ACTPRICES")einen Breakpunkt setzen, dann sollte in RETURN stehen, was da falsch läuft. Ich kriege z.B. die korrekte Meldung "Kostenrechnungskreis 1000 existiert nicht".

leMoi66
12.09.2017, 11:55
Vielen Dank! Das hat mich zur Lösung gebracht.

Für die Leistungsart wirdin der SAP Doku eine Feldlänge von 6 Stellen vorgegeben -> Also statt "110", "000110".

Wie sich herausgestellt hat, sind es in diesem Fall nur 3 Stellen.

Vielen Dank!

Scorefun
12.09.2017, 12:15
Vielen Dank! Das hat mich zur Lösung gebracht.

Für die Leistungsart wirdin der SAP Doku eine Feldlänge von 6 Stellen vorgegeben -> Also statt "110", "000110".


Das schrieb ich doch schon in #4 mit den Feldlängen...

leMoi66
12.09.2017, 13:25
Absolut!

Nur habe ich nicht herausgefunden, was genau nicht stimmte (und bin nicht davon ausgegangen, dass die SAP Doku falsch ist :-D )