VB.Net – Mit RFC beliebige SAP Tabelle als Dataview einlesen inkl. ABAP Sourcecode

Mit dieser Funktion kann man ein Dataview bilden was auf einer beliebigen SAP Tabelle basiert. Bei größeren Datenmengen gibt es schonmal Probleme. Also bitte den Filter richtig setzen. Das zugehörige ABAP Programm könnt ihr weiter unten herunterladen.

So wird es gemacht:

    '============================================
    ' .NET Beispiel in Visual Basic .Net
    ' © wilfried.bitz@bridgesolution.de
    '============================================
 
    Public Function SAP_Read_Table_DV_Init( _
        ByRef SAP_Table As String, _
        ByVal SAP_Field_Sort As String, _
        ByVal strFilter As String, _
        ByVal lngRowCount As Long) As DataView
        SAP_Read_Table_DV_Init = Nothing
 
        '----------------------------------------
        Dim strProzedur As String = "SAP_Read_Table_DV_Init"
        Dim strLogPfad As String = "G:\LPnet_LOG\RFC\"
        '----------------------------------------
 
        '----------------------------------------
        Dim mySAP As Object = Nothing
        Dim RFC_READ_TABLE As Object
        Dim eQUERY_TAB As Object
        Dim eDELIMITER As Object
        Dim eQUERY_SORT As Object
        Dim tOPTIONS As Object
        Dim R3_RFC_READ_TABLE As Integer
        Dim SapDataTable As Object
        Dim SapFieldTable As Object
        '----------------------------------------
 
        Try
 
            '------------------------------------
            If Not gLP.SAP_IsConnected = 1 Then
                Exit Function
            End If
            '------------------------------------
 
            '------------------------------------
            'Lokales SAP Objekt
            mySAP = SAP_LogOn(gLP)
            mySAP.LogFileName = strLogPfad & gLP.LP_Benutzer & "_" & strProzedur & ".txt"
            mySAP.LogLevel = 9
            RFC_READ_TABLE = mySAP.Add("ZD_RFC_READ_TABLE")
            '------------------------------------
 
            '------------------------------------
            RFC_READ_TABLE.Exports("ROWCOUNT") = CStr(lngRowCount)
            eQUERY_TAB = RFC_READ_TABLE.Exports("QUERY_TABLE")
            eDELIMITER = RFC_READ_TABLE.Exports("DELIMITER")
            eQUERY_SORT = RFC_READ_TABLE.Exports("STRSORT")
            tOPTIONS = RFC_READ_TABLE.Tables("OPTIONS")
 
            SapDataTable = RFC_READ_TABLE.Tables("DATA")
            SapFieldTable = RFC_READ_TABLE.Tables("FIELDS")
 
            eQUERY_TAB.Value = SAP_Table
            eQUERY_SORT.Value = SAP_Field_Sort
            eDELIMITER.Value = "|"
            SapDataTable.freetable()
            SapFieldTable.freetable()
            '------------------------------------
 
            '------------------------------------
            'Für Einschränkungen > 72 Zeichen mussen mehrere Zeilen eingefügt werden!
            If strFilter <> "" Then
                tOPTIONS.AppendRow()
                tOPTIONS.cell(tOPTIONS.RowCount, 1) = strFilter ' AND LENG NE 0"
            End If
            '------------------------------------
 
            '------------------------------------
            'FuBau ausführen
            If RFC_READ_TABLE.Call = True Then
                If SapDataTable.RowCount > 0 Then 'Erfolgreich, Daten erhalten
                    R3_RFC_READ_TABLE = 1
                Else 'Erfolgreich, keine Daten erhalten
                    R3_RFC_READ_TABLE = 0
                End If
            Else 'Fehlgeschlagen
                'Err.Raise(9096, DefaultErrorSource, "Der RFC-Funktionsbaustein 
                'RFC_READ_TABLE' lieferte die Exception '" + RFC_READ_TABLE.EXCEPTION + "'")
                MsgBox("SAP Meldung -> ZD_RFC_READ_TABLE: " & RFC_READ_TABLE.EXCEPTION)
            End If
            '------------------------------------
 
            '------------------------------------
            'Es stehen nun die Ergebnisse in zwei Variablen zur Verfügung: 
            '- SapDataTable enthält die Daten
            '- SapFieldTable enthält Feldinformationen
            '------------------------------------
 
            '------------------------------------
            'temporäres Dataview
            Dim strField As String
            Dim intRow As Integer
            Dim strWert As String
            Dim myDataTable As DataTable = New DataTable("Temp")
            For intc = 1 To SapFieldTable.RowCount
                'Alle Felder auslesen
                strField = SapFieldTable(intc, 1)
                myDataTable = SQL_DT_Col_Add(myDataTable, strField)
                Debug.Print(strField)
            Next intc
            Dim myDV_Temp As DataView = New DataView(myDataTable)
            Dim int_DV_Temp As Integer
            '------------------------------------
 
            '------------------------------------
            'Zurückgegebene Zeilen ggf. auslesen und 
            'Dataview oder Recordset füllen
            If R3_RFC_READ_TABLE = 1 Then
                For inti = 1 To SapDataTable.RowCount
                    intRow = intRow + 1
                    int_DV_Temp = int_DV_Temp + 1
                    myDV_Temp.AddNew()
                    For intc = 1 To SapFieldTable.RowCount
                        'Alle Felder auslesen
                        strField = SapFieldTable(intc, 1)
                        strWert = CStr(ConvColStringRead(SapDataTable(intRow, 1), intc, "|"))
                        myDV_Temp(int_DV_Temp - 1).Item(strField) = strWert
                        Debug.Print(strWert)
                    Next intc
                Next inti
            End If
            '------------------------------------
 
            '------------------------------------
            'Dataview oder Recordset Rückgabe
            SAP_Read_Table_DV_Init = myDV_Temp
            RFC_READ_TABLE = Nothing
            '------------------------------------
 
        Catch ex As Exception
        Finally
            '------------------------------------
            'lokale SAP Session sauber schließen
            mySAP = SAP_LogOff(mySAP, strProzedur)
            '------------------------------------
 
        End Try
 
    End Function

ABAP Programm:

    '============================================
    ' ABAP Beispiel in SAP Abap geschrieben
    ' © wilfried.bitz@bridgesolution.de
    '============================================
 
FUNCTION ZD_RFC_READ_TABLE.
*"----------------------------------------------------------------------
*"*"Lokale Schnittstelle:
*"  IMPORTING
*"     VALUE(QUERY_TABLE) TYPE  DD02L-TABNAME
*"     VALUE(DELIMITER) TYPE  SONV-FLAG DEFAULT SPACE
*"     VALUE(NO_DATA) TYPE  SONV-FLAG DEFAULT SPACE
*"     VALUE(ROWSKIPS) TYPE  SOID-ACCNT DEFAULT 0
*"     VALUE(ROWCOUNT) TYPE  SOID-ACCNT DEFAULT 0
*"     VALUE(STRSORT) TYPE  STRING_PP OPTIONAL
*"  TABLES
*"      OPTIONS STRUCTURE  RFC_DB_OPT
*"      FIELDS STRUCTURE  RFC_DB_FLD
*"      DATA STRUCTURE  TAB512
*"  EXCEPTIONS
*"      TABLE_NOT_AVAILABLE
*"      TABLE_WITHOUT_DATA
*"      OPTION_NOT_VALID
*"      FIELD_NOT_VALID
*"      NOT_AUTHORIZED
*"      DATA_BUFFER_EXCEEDED
*"----------------------------------------------------------------------
"
CALL FUNCTION 'VIEW_AUTHORITY_CHECK'
     EXPORTING
          VIEW_ACTION                    = 'S'
          VIEW_NAME                      = QUERY_TABLE
     EXCEPTIONS
          NO_AUTHORITY                   = 2
          NO_CLIENTINDEPENDENT_AUTHORITY = 2
          NO_LINEDEPENDENT_AUTHORITY     = 2
          OTHERS                         = 1.
 
IF SY-SUBRC = 2.
  RAISE NOT_AUTHORIZED.
ELSEIF SY-SUBRC = 1.
  RAISE TABLE_NOT_AVAILABLE.
ENDIF.
 
* ----------------------------------------------------------------------
*  find out about the structure of QUERY_TABLE
* ----------------------------------------------------------------------
DATA BEGIN OF TABLE_STRUCTURE OCCURS 10.
        INCLUDE STRUCTURE DFIES.
DATA END OF TABLE_STRUCTURE.
"DATA TABLE_HEADER LIKE X030L.
DATA TABLE_TYPE TYPE DD02V-TABCLASS.
 
CALL FUNCTION 'DDIF_FIELDINFO_GET'
  EXPORTING
    TABNAME              = QUERY_TABLE
*   FIELDNAME            = ' '
*   LANGU                = SY-LANGU
*   LFIELDNAME           = ' '
*   ALL_TYPES            = ' '
*   GROUP_NAMES          = ' '
  IMPORTING
*   X030L_WA             =
    DDOBJTYPE            = TABLE_TYPE
*   DFIES_WA             =
*   LINES_DESCR          =
  TABLES
    DFIES_TAB            = TABLE_STRUCTURE
*   FIXED_VALUES         =
  EXCEPTIONS
    NOT_FOUND            = 1
    INTERNAL_ERROR       = 2
    OTHERS               = 3
          .
IF SY-SUBRC <> 0.
  RAISE TABLE_NOT_AVAILABLE.
ENDIF.
IF TABLE_TYPE = 'INTTAB'.
  RAISE TABLE_WITHOUT_DATA.
ENDIF.
 
* ----------------------------------------------------------------------
*  isolate first field of DATA as output field
*  (i.e. allow for changes to structure DATA!)
* ----------------------------------------------------------------------
DATA LINE_LENGTH TYPE I.
FIELD-SYMBOLS <D>.
ASSIGN COMPONENT 0 OF STRUCTURE DATA TO <D>.
DESCRIBE FIELD <D> LENGTH LINE_LENGTH in character mode.
 
* ----------------------------------------------------------------------
*  if FIELDS are not specified, read all available fields
* ----------------------------------------------------------------------
DATA NUMBER_OF_FIELDS TYPE I.
DATA lngZaehler TYPE I.
 
DESCRIBE TABLE FIELDS LINES NUMBER_OF_FIELDS.
IF NUMBER_OF_FIELDS = 0.
  LOOP AT TABLE_STRUCTURE.
    lngZaehler = lngZaehler + 1.
    IF lngZaehler > 50. "maximal 50 Felder
      EXIT.
    ENDIF.
    MOVE TABLE_STRUCTURE-FIELDNAME TO FIELDS-FIELDNAME.
    APPEND FIELDS.
 
  ENDLOOP.
ENDIF.
 
* ----------------------------------------------------------------------
*  for each field which has to be read, copy structure information
*  into tables FIELDS_INT (internal use) and FIELDS (output)
* ----------------------------------------------------------------------
DATA: BEGIN OF FIELDS_INT OCCURS 10,
        FIELDNAME  LIKE TABLE_STRUCTURE-FIELDNAME,
        TYPE       LIKE TABLE_STRUCTURE-INTTYPE,
        DECIMALS   LIKE TABLE_STRUCTURE-DECIMALS,
        LENGTH_SRC LIKE TABLE_STRUCTURE-INTLEN,
        LENGTH_DST LIKE TABLE_STRUCTURE-LENG,
        OFFSET_SRC LIKE TABLE_STRUCTURE-OFFSET,
        OFFSET_DST LIKE TABLE_STRUCTURE-OFFSET,
      END OF FIELDS_INT,
      LINE_CURSOR TYPE I.
 
LINE_CURSOR = 0.
*  for each field which has to be read ...
LOOP AT FIELDS.
 
  READ TABLE TABLE_STRUCTURE WITH KEY FIELDNAME = FIELDS-FIELDNAME.
  IF SY-SUBRC NE 0.
    RAISE FIELD_NOT_VALID.
  ENDIF.
 
* compute the place for field contents in DATA rows:
* if not first field in row, allow space for delimiter
  IF LINE_CURSOR <> 0.
    IF NO_DATA EQ SPACE AND DELIMITER NE SPACE.
      MOVE DELIMITER TO DATA+LINE_CURSOR.
    ENDIF.
    LINE_CURSOR = LINE_CURSOR + STRLEN( DELIMITER ).
  ENDIF.
 
* ... copy structure information into tables FIELDS_INT
* (which is used internally during SELECT) ...
  FIELDS_INT-FIELDNAME  = TABLE_STRUCTURE-FIELDNAME.
  FIELDS_INT-LENGTH_SRC = TABLE_STRUCTURE-INTLEN.
  FIELDS_INT-LENGTH_DST = TABLE_STRUCTURE-LENG.
  FIELDS_INT-OFFSET_SRC = TABLE_STRUCTURE-OFFSET.
  FIELDS_INT-OFFSET_DST = LINE_CURSOR.
  FIELDS_INT-TYPE       = TABLE_STRUCTURE-INTTYPE.
  FIELDS_INT-DECIMALS   = TABLE_STRUCTURE-DECIMALS.
* compute the place for contents of next field in DATA rows
  LINE_CURSOR = LINE_CURSOR + TABLE_STRUCTURE-LENG.
  IF LINE_CURSOR > LINE_LENGTH AND NO_DATA EQ SPACE.
    RAISE DATA_BUFFER_EXCEEDED.
  ENDIF.
  APPEND FIELDS_INT.
 
* ... and into table FIELDS (which is output to the caller)
  FIELDS-FIELDTEXT = TABLE_STRUCTURE-FIELDTEXT.
  FIELDS-TYPE      = TABLE_STRUCTURE-INTTYPE.
  FIELDS-LENGTH    = FIELDS_INT-LENGTH_DST.
  FIELDS-OFFSET    = FIELDS_INT-OFFSET_DST.
  MODIFY FIELDS.
 
ENDLOOP.
* end of loop at FIELDS
 
* ----------------------------------------------------------------------
*  read data from the database and copy relevant portions into DATA
* ----------------------------------------------------------------------
* output data only if NO_DATA equals space (otherwise the structure
* information in FIELDS is the only result of the module)
IF NO_DATA EQ SPACE.
 
DATA: BEGIN OF WORK, BUFFER(30000), END OF WORK.
 
FIELD-SYMBOLS: <WA> TYPE ANY, <COMP> TYPE ANY.
ASSIGN WORK TO <WA> CASTING TYPE (QUERY_TABLE).
 
IF ROWCOUNT > 0.
  ROWCOUNT = ROWCOUNT + ROWSKIPS.
ENDIF.
 
  SELECT * FROM (QUERY_TABLE) INTO <WA> ORDER BY (STRSORT)  WHERE (OPTIONS).
 
    IF SY-DBCNT GT ROWSKIPS.
 
*   copy all relevant fields into DATA (output) table
      LOOP AT FIELDS_INT.
        IF FIELDS_INT-TYPE = 'P'.
        ASSIGN COMPONENT FIELDS_INT-FIELDNAME
            OF STRUCTURE <WA> TO <COMP>
            TYPE     FIELDS_INT-TYPE
            DECIMALS FIELDS_INT-DECIMALS.
        ELSE.
        ASSIGN COMPONENT FIELDS_INT-FIELDNAME
            OF STRUCTURE <WA> TO <COMP>
            TYPE     FIELDS_INT-TYPE.
        ENDIF.
        MOVE <COMP> TO
            <D>+FIELDS_INT-OFFSET_DST(FIELDS_INT-LENGTH_DST).
      ENDLOOP.
*   end of loop at FIELDS_INT
      APPEND DATA.
 
      IF ROWCOUNT > 0 AND SY-DBCNT GE ROWCOUNT. EXIT. ENDIF.
 
    ENDIF.
 
  ENDSELECT.
 
ENDIF.
 
ENDFUNCTION.

Spendierst du mir eine Tasse Kaffee? Ich würd mich riesig freuen. DANKE !! 🙂


5 Kommentare

Joshua Weltle · 3. Mai 2017 um 11:15

Bin leider noch Neuling…
Habe mit VBA (Excel) begonnen und habe mich jetzt auf VisualStudio VB.net gesteigert.
eine Oracle Datenbank auslesen stellt sich als kein problem mehr da!
SAP leider schon… Ich schaffe es eine Verbindung auf zu bauen und die SAP SytemInfo damit ab zu rufen.
Was ich aber brauche (ich hatte gehoft das schaffe ich mit ihrem Code) ist eine möglichkeit über ein SQL Select auf Tabelle X in SAP geziehlte daten heraus zu holen.

    admin · 3. Mai 2017 um 12:48

    Hallo Joshua,
    mit diesen 2 Funktionen kannst du beliebige SAP Tabellen abfragen. Du mußt natürlich eine Session öffnen und die ABAP Funktion im SAP installieren.
    Gruß Wilfried

      Joshua Weltle · 3. Mai 2017 um 12:54

      Hallo Wilfried,

      Danke für deine schnelle Antwort.
      Mit ABAP kenne ich mich überhaupt nicht aus!
      Kann ich das einfach unsren Programmierern geben und die kopieren das, oder müssen sie noch was anpassen?

      Gruß
      Joshua

        admin · 3. Mai 2017 um 13:12

        Hallo Joshua,
        das kannst du machen. Es handelt sich dabei um eine modifizierte ABAP RFC Funktion innerhalb des SAP’s. VB.Net kommuniziert mit RFC Funktionen auf der SAP Seite. Ein SAP Programmierer weiß bescheid. Anpassungen sollten nicht notwendig sein. Gib mal bescheid wie du mit deinem Projekt vorwärts kommst.

        Gruß Wilfried

          Joshua Weltle · 3. Mai 2017 um 13:28

          Hallo Wilfried,
          Alles klar dann Organisiere ich das.
          Ja ich gebe dir gern bescheid wie es voran geht.
          Zur Info es wird am ende ein Lagerverwaltungssystem!
          Es Funktioniert bereits mit einigen umwegen welche ich hiermit beseitigen muss!
          Ich lass mir momentan mit einem BI-tool welches die Daten aus SAP alle 10 minuten läd in eine txt Datei schreiben, die ich dann mit meinem Code auslese.
          Problem hier ist das das BI-Tool bereits mega überlastet ist und SAP auch nichts gutes tue wenn ich all 10min ein full table scann mache ^^.
          Ich habe 9 verschiedene Etiketten aus 3 Unterschiedlichen Datenquellen (MES-System, SAP und Datenverwaltungssystem). Das ist die Herausforerung, ach und kein W-Lan 😀
          Danke
          Joshua

Schreibe einen Kommentar zu Joshua Weltle Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.