SAP Query is a very interesting and easy to use approach to create reports which contains data outputs from SAP tables. With SAP Query you have the possibility to use tables, combine tables with joins and other data sources to get the data you need. You can find a very good description how to handle SAP Query at the SAP Community.
Yesterday at the UiPath DevCon I had a very interesting discussion in the AMER room about this approach. And the question here was: How can I use this approach also in UiPath? I remembered that there is a remote enabled function module (RFM) that can be used to do this. The name of the RFM is RSAQ_REMOTE_QUERY_CALL.
With the combination of SAP Query and this RFM you have the possibility to define queries on an easy and flexible way and to use the results in your UiPath workflow. In my example I use only one table, in this case SFLIGHT. Via transaction code (TAC) SQVI I choose as data source Table and the table SFLIGHT with a few fields.
To try how to call the RFM I use TAC SE37 and set the necessary parameters. The QUERY name, the USERGROUP, which is generated automatically with SQVI, and the VARIANT of the generated report. Important is here to set SKIP_SELSCREEN and DATA_TO_MEMORY.

After the execution we see the results in the export parameters and in the tables.

The table LISTDESC contains the information about the fields.
The table LDATA contains the result of the query. This format looks a little bit weird.

With the RFM Code Generator I generated the following C# code . Only in the section to output the content I have added a few lines manually.
//-RFM Code Generator Begin (C#)----------------------------------------
RfcConfigParameters cfgParams = new RfcConfigParameters();
cfgParams.Add("NAME", "Test");
cfgParams.Add("ASHOST", "YourSAPHost");
cfgParams.Add("CLIENT", "099");
cfgParams.Add("USER", "Stefan");
cfgParams.Add("PASSWD", "secret");
cfgParams.Add("LANGUAGE", "EN");
try {
RfcDestination destination = RfcDestinationManager.GetDestination(cfgParams);
IRfcFunction rfcFunction = destination.Repository.CreateFunction("RSAQ_REMOTE_QUERY_CALL");
//-Tables-------------------------------------------------------------
IRfcTable tblFPAIRS = rfcFunction.GetTable("FPAIRS");
IRfcTable tblLDATA = rfcFunction.GetTable("LDATA");
IRfcTable tblLISTDESC = rfcFunction.GetTable("LISTDESC");
IRfcTable tblSELECTION_TABLE = rfcFunction.GetTable("SELECTION_TABLE");
//-Import-------------------------------------------------------------
rfcFunction.SetValue("DATA_TO_MEMORY", "X");
rfcFunction.SetValue("DBACC", 0);
rfcFunction.SetValue("EXTERNAL_PRESENTATION", "");
rfcFunction.SetValue("QUERY", "ZTEST");
rfcFunction.SetValue("SKIP_SELSCREEN", "X");
rfcFunction.SetValue("USERGROUP", "SYSTQV000001");
rfcFunction.SetValue("VARIANT", "ZTEST");
rfcFunction.SetValue("WORKSPACE", "");
//-Invoke-------------------------------------------------------------
rfcFunction.Invoke(destination);
//-Export-------------------------------------------------------------
string strLIST_ID = rfcFunction.GetString("LIST_ID");
string strLISTTEXT = rfcFunction.GetString("LISTTEXT");
string strPROGRAM = rfcFunction.GetString("PROGRAM");
string strUSED_VARIANT = rfcFunction.GetString("USED_VARIANT");
//-Output of SAP Query------------------------------------------------
string Output = string.Empty;
foreach(var Record in tblLDATA) {
string strLINE = Record.GetString("LINE");
Output += strLINE;
}
string[] Lines = Output.Split(';');
foreach(string Line in Lines) {
Console.WriteLine(Line);
}
} catch(Exception ex) {
Console.WriteLine(ex.Message);
}
//-RFM Code Generator End-----------------------------------------------
This code can now paste into an Invoke Code activity.
There is still some work to do here now, such as splitting each row into the columns and extracting the value. But this is not witchcraft.
Conclusion
As can be seen, this approach can be used to achieve a very high level of individualization in get the data from an SAP backend system and use the data in an UiPath workflow. In the course of a further development I could imagine that only the necessary parameters are to be passed (QUERY, USERGROUP and VARIANT) and that as a result a data table is returned, because the column names and types are well known in the table LISTDESC. However, this is only one step to see if it basically works. And yes, it does. ![]()















