Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 

前言


当您在使用SAP 分析云时,您可以会需要从不同的外部环境中调用数据,SAP分析云供了许多和SAP/非 SAP相关的集成拓展功能。这些功能可用于将数据按自动或手动导入到计划模型中,也支持从Flat文件加载。

但是对于某些特殊用例,他们需要终端用户(而不是系统管理员)手动操作完成:需要将交易数据从Flat文件上传到 SAP 分析云的计划模型中。例如,在实际操作中可能需要财务分析师上传财务数据,作为在 SAP 分析云表格微件中手动输入数据的补充。这些用户通常没有访问模型数据管理的扩展权限,因为它可能导致不受控制主数据、交易数据的更改。

本篇博客将介绍如何使用SAP分析云的分析应用功能解决此问题。对于这种方法,用户不需要访问计划模型数据管理。注意:此Flat文件上传解决方案旨在用于有限的数据集。

解决方案


本案例仅使用SAP 分析云的标准组件,我们将用到数据集和分析应用。

首先,用户需要将Flat文件或 Excel 加载到数据集对象中。由于数据集具有从文件加载标准化数据的能力,您无需对主数据和维度做维护。此外,您还可以对数据进行转换。在数据加载到数据集中后,接下来您可以使用分析应用程序查看数据集中的数据,并可以将其复制到所需的计划模型中了。

下面我们来详细看一下这个方案的底层技术逻辑。



技术逻辑


步骤 1. 将Flat文件中的数据加载到数据集中


本数据集用于将初始数据上传到 SAP 分析云。它可以由终端用户创建,也可以使用预先创建的数据集。用户还可以创建多个数据集,例如,用于不同版本的数据。


数据导入/重新导入数据集


此外,数据集在我们的任务上下文中具有以下有用的特征:

  • 用户可以将 csv 或 xls 文件拖放到 SAP 分析云界面创建。

  • 无需维护主数据以及维度和度量。

  • 可以包含数据转换规则(以启用类似于 BPC中的标准转换文件的逻辑)。

  • 可多次使用:您可以重新加载数据,并且将应用到所有先前创建的转换规则。



数据的转换规则


经过这一步骤后,我们就已经将Flat文件中的数据加载到数据集中了。

步骤 2. 使用分析应用程序将数据集中的数据加载到计划模型中


我们已经将Flat文件中的数据加载到数据集中并进行转换,现在需要将这些数据加载到计划模型中








选项卡 1. 打开数据集并预览

(注意:分析应用程序的界面包含 2 个部分,使用 Tab Strip 小部件在逻辑上分为 2 个选项卡)


打开数据集和预览数据选项卡


注意:在这个界面中,我们有数据预览选项卡和一个执行打开数据集选择对话框的按钮

在单击“打开数据集”按键后,将出现“打开数据集/模型”对话框。在此对话框中,我们选择在步骤 1 中上传数据的源数据集。完成后,数据将显示在预览表中,相关过滤器将应用于选项卡 2 中的结果表(结果表中仅显示计划模型的一部分,与数据上传相关)。








选项卡 2. 将数据从预览数据表复制到计划模型表

当我们点击按钮 Next 时,将会显示预览界面。这里我们需要点击加载按钮。在预览表 tblPreview 中的数据将逐条被复制到结果表 tblResult 中。之后,我们可以查看数据,在表格​​中对其进行编辑,并使用标准 SAP 分析云 界面发布或还原数据。


结果预览和发布/还原选项卡



步骤 2 的结果将数据发布到计划模型中。

代码的逻辑:


现在让我们看看这些接口背后的代码。注意,此代码以说明为主,某些参数在脚本中直接指定可以通过参数或基于特定逻辑/映射动态导出数据。

选项卡 1 - 按钮“打开数据集..”(btnOpenDataset),点击事件:








// Open dataset / model dialog to allow user to select the required source dataset

tblPreview.openSelectModelDialog();

 

// Making all dataset dimensions visible in the table

var dimList = tblPreview.getDataSource().getDimensions();

for (var i=0; i< dimList.length; i++)

{

tblPreview.addDimensionToRows(dimList[i],i);

}

 

// Making Date hierarchy flat, as by default it opens YQM

tblPreview.getDataSource().setHierarchy("Date","@FlatHierarchy");

 

// Showing preview table with dataset data

tblPreview.setVisible(true);

 

// Populating values from dataset into arrays for applying them as filters for the target table

var rsData = tblPreview.getDataSource().getResultSet();

 

var accMembers = ArrayUtils.create(Type.string);

var ccMembers = ArrayUtils.create(Type.string);

var dsMembers = ArrayUtils.create(Type.string);

var dateMembers = ArrayUtils.create(Type.string);

var baMembers = ArrayUtils.create(Type.string);

 

// Going through all records of dataset and assigning values to arrays

for (var k=0; k< rsData.length; k++)

{

accMembers[k] = "[Account].[parentId].&[" + rsData[k]["Account"].id + "]";

ccMembers[k]= "[Cost_center].[CC_H].&["+  rsData[k]["Cost_Center"].id  + "]";

dsMembers[k] = "Input";

dateMembers[k] = rsData[k]["Date"].id.substring(0,4)+rsData[k]["Date"].id.substring(5,7);

baMembers[k] = rsData[k]["Business_Area"].id;

}

 

// Setting filters of Result table on the second page to show only relevant PoV

tblResult.getDataSource().setDimensionFilter("Account",accMembers);

tblResult.getDataSource().setDimensionFilter("Cost_center",ccMembers);

tblResult.getDataSource().setDimensionFilter("Data_source",dsMembers);

tblResult.getDataSource().setDimensionFilter("Date",dateMembers);

tblResult.getDataSource().setDimensionFilter("Business_Area",baMembers);

 

// Showing result table with applied filters

tblResult.setVisible(true);

选项卡 2 – 按钮“加载”(btnLoad),点击事件:








// Copy lines & submit

 

// Get set of data from preview table with loaded dataset

var rsData = tblPreview.getDataSource().getResultSet();

 

// One by one copy values from source table into result (target) table

for (var i=0; i< tblPreview.getRowCount(); i++)

{

// Logic to read records from source table and enter into the target table

// Reading values of Account and Cost center and adjusting to include hierarchy elements

// In case needed, the code can be enhanced with dynamic hier

var Account = "[Account].[parentId].&[" + rsData[i]["Account"].id + "]" ;

var CostCenter = "[Cost_center].[CC_H].&["+  rsData[i]["Cost_Center"].id  + "]";

// Writing values into target table with planning model

tblResult.getPlanning().setUserInput({

"Account":Account,

"Business_Area":rsData[i]["Business_Area"].id, // Business Area dimension

"Data_source":"Input",    // Hardcoded for simplicity. In case needed, logic is the same as Account and Cost center

"Version":"public.Actual", // Hardcoded for simplicity. In case needed, logic is the same as Account and Cost center

"Date":rsData[i]["Date"].id.substring(0,4)+rsData[i]["Date"].id.substring(5,7), // Date dimension

"Cost_center":CostCenter,

[Alias.MeasureDimension]:"SignedData"},rsData[i][Alias.MeasureDimension].rawValue); // Value

}

 

// Submitting the data to show it in table

tblResult.getPlanning().submitData();

其他扩展和限制


以上的讲解是基于基本场景。为了使应用程序更健壮

  1. 打开数据集并显示缺失的主数据成员,Accounts/Cost center 的代码示例如下所示:










// Forming Accounts array

var arrDestAcctMembers = ArrayUtils.create(Type.MemberInfo);

arrDestAcctMembers = tblResult.getDataSource().getMembers("Account");

var strDestAcctMembers = ArrayUtils.create(Type.string);

for (k=0; k< arrDestAcctMembers.length; k++)

{

strDestAcctMembers[k] = arrDestAcctMembers[k].id;

}

 

// Forming Cost Centers array

var arrDestCCtMembers = ArrayUtils.create(Type.MemberInfo);

arrDestCCtMembers = tblResult.getDataSource().getMembers("Cost_center");

var strDestCCtMembers = ArrayUtils.create(Type.string);

for (k=0; k< arrDestCCtMembers.length; k++)

{

strDestCCtMembers[k] = arrDestCCtMembers[k].id;

}

// Account / Cost centers check check

for (k=0; k< rsData.length; k++)

{

if (strDestAcctMembers.indexOf("[Account].[parentId].&[" + rsData[k]["Account"].id + "]") === -1)

{

lbLog.addItem("A"+k.toString(), "Account " +  rsData[k]["Account"].id  + " does not exist in target model");

}

if (strDestCCtMembers.indexOf("[Cost_center].[CC_H].&["+  rsData[k]["Cost_Center"].id  + "]") === -1)

{

lbLog.addItem("C"+k.toString(), "Cost center " +  rsData[k]["Cost_Center"].id  + " does not exist in target model");

}

}

lbLog.addItem("done", "Dataset check completed");

lbLog.setVisible(true);

Listbox lbLog 在这里用于显示检查的主数据成员的日志。

2.由于结果是通过前端查询获取的,查询存在数据量的限制。上述解决方案适用于最多 500 条记录的数据集,无需任何额外操作。当记录数超过500条时,我们需要编辑预览表的钻取限制:


编辑钻取限制


当记录超过1500条时,您需要调整逻辑以将数据从 tabPreview 批量复制到 tabResult中。

  1. 除了主数据检查外,还可以添加扩展的验证规则,例如只加载选定的主数据成员组合。

  2. 在选项卡 1 上可以添加筛选器,只复制选定的数据子集。


结论


本篇博客展示了如何使用数据集和分析应用程序的功能为用户创建Flat文件上传解决方案,新功能用户无需访问计划模型的数据管理和涉及其他解决方案和组件。此外,它可以根据特定的业务需求使用拓展插件。欢迎您在SAP分析云中使用这一功能,另外获取更多技术文章,欢迎访问SAP分析云,了解更多技术干货!

 

原文章:Flat file upload to SAC Planning model with analytic application and dataset

原作者:lopatinvyu