ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SAP物料特性值查询:CLAF_CLASSIFICATION_OF_OBJECTS函数详解与实战

SAP物料特性值查询:CLAF_CLASSIFICATION_OF_OBJECTS函数详解与实战 1. 从一次物料主数据查询的“卡壳”说起在SAP的物料管理MM或生产计划PP模块里我们经常会遇到一个场景需要根据物料的某些特性比如颜色、尺寸、等级来筛选或处理数据。比如你想找出所有“颜色为红色”且“尺寸为M”的成品物料或者想批量修改一批具有特定“环保等级”的原材料。这时候你可能会很自然地想到去查表比如MARA通用物料数据、MARC工厂级物料数据但很快就会发现这些标准表里并没有直接存储这些“特性值”。这些特性值在SAP中属于“分类”Classification系统的范畴。物料、设备、批次等主数据对象都可以被分配到一个或多个“类”Class中而类则由一系列“特性”Characteristic组成特性的具体内容就是“特性值”Characteristic Value。这套体系非常灵活但也带来了查询上的复杂性数据并不在物料主表里而是分散在分类相关的透明表如AUSP、KSSK中表间关联复杂直接写SQL或ABAP代码去关联查询对于不熟悉分类表结构的人来说是个不小的挑战。就在上周我协助一位同事处理一个报表需求时就遇到了这个问题。他需要导出一批物料的“最小包装量”和“安全库存等级”这两个信息在物料主数据里没有标准字段而是作为特性维护在分类里。看着他准备写一个冗长的、包含INNER JOIN KSSK ON... LEFT JOIN AUSP ON...的复杂SQL时我打断了他“别这么麻烦SAP其实提供了一个现成的、封装好的函数Function Module来专门干这个事儿。” 这个函数就是CLAF_CLASSIFICATION_OF_OBJECTS。今天我们就来深入聊聊这个在获取对象尤其是物料特性值时堪称“瑞士军刀”的FM它的工作原理、核心参数、使用技巧以及那些官方文档里不会写的“坑”。2.CLAF_CLASSIFICATION_OF_OBJECTS功能全景与核心参数拆解这个FM的名字直译过来就是“对象的分类”它的核心使命就是根据你提供的对象关键信息比如物料号、设备号等返回该对象在所有相关类下分配的所有特性及其值。它是一个“只读”函数不会修改任何数据纯粹用于查询。2.1 输入参数告诉函数你要查什么调用这个FM最关键的就是准备好输入参数。它主要有两个输入结构IMPORTING参数OBJECT 这是一个KLAH-CLASS类型的结构但实际上我们只用它来传递对象的关键信息。最重要的字段是OBJEK对象的内部编号Internal Number。这是SAP系统中唯一标识一个主数据对象的键值。对于物料MATNR来说它并不是我们常见的物料号如MAT-0001而是通过函数CONVERSION_EXIT_ALPHA_INPUT转换后再调用函数MARA_SINGLE_READ或直接查询表MARA得到的MARA-MATNR内部格式。这是最容易出错的地方之一。通常我们需要先将外部物料号可能带前导零转换为内部格式或者直接使用MARA-MATNR字段的值。OBTAB对象表名。这是一个固定的值告诉系统你要查询的是什么类型的对象。对于物料主数据这个值就是‘MARA’。其他常见对象类型还有设备EQUI、功能位置IFLOT、批次MCH1等。KLART类类型Class Type。这定义了类的用途比如物料主数据的类类型通常是‘001’物料类批次分类是‘022’批次类供应商分类可能是‘032’。如果你不确定对象属于哪个类类型可以留空‘ ’函数会尝试查找所有类类型下的分类。但为了提高性能和准确性建议明确指定。OBJECT_TABLE 这是一个KLAH-OBJEK_TAB类型的表。它允许你一次性查询多个对象。其行结构与OBJECT参数类似包含OBJEK、OBTAB、KLART字段。如果你只需要查单个对象使用OBJECT参数更简单如果需要批量查询比如一个物料清单则填充这个内表效率更高。2.2 输出参数函数返回了什么函数处理完成后结果会通过以下参数返回CLASSIFICATION 这是一个BAPI1003_ALLOC_VALUES类型的复杂内表也是我们最关心的部分。它包含了查询对象的所有分类详情。每一行代表一个“特性分配”。我们来看几个关键字段CLASS 类编号。CLASSTYPE 类类型。OBJKEY 对象键与输入的OBJEK对应。CHARACT特性编号如‘COLOR’或‘SIZE’。CHARACT_DESCR 特性的描述文本。VALUE特性的值字符型。对于大多数文本、数字、日期类型的特性值就存储在这里。VALUE_NEUTRAL 特性的中性值内部值。对于一些有代码表的特性这里存储的是代码如‘RED’而VALUE里是对应的描述如‘红色’。VALUE_DESCR 特性值的描述长文本。DATA_TYPE 特性的数据类型如‘CHAR’字符‘NUM’数字‘DATE’日期等。FROM/TO 对于区间值如数值范围、日期范围这里定义了上下限。这个内表的结构非常清晰基本上拿到了它你就拿到了对象分类数据的“全家桶”。RETURN 一个BAPIRET2类型的消息内表。用于返回函数执行过程中的警告、错误或成功信息。务必在调用后检查这个内表以确认数据是否成功获取或者是否存在对象未分类等情况。2.3 其他参数LANGUAGE 指定返回的描述文本如CHARACT_DESCR,VALUE_DESCR的语言。默认是SY-LANGU当前登录语言。KEY_DATE 指定一个关键日期。分类数据可能有有效期Valid From/To此参数用于获取在指定日期有效的分类数据。默认为当前日期SY-DATUM。WITH_INTERVALS 一个标志位如果设置为‘X’函数会额外处理区间类型的特性将其展开。通常保持默认即可。3. 实战演练ABAP代码示例与逐行解析理论说得再多不如一行代码。下面我们通过一个完整的ABAP函数示例来演示如何调用CLAF_CLASSIFICATION_OF_OBJECTS获取一个物料的特性值。假设我们的需求是输入一个物料号外部格式如100-100获取其所有分类下的特性并找到名为‘MIN_PACK_QTY’最小包装量的特性值。REPORT ZGET_MAT_CHAR_VALUE. DATA: lv_matnr_ext TYPE matnr, “ 外部物料号用户输入 lv_matnr_int TYPE mara-matnr, “ 内部物料号 ls_object TYPE klah, lt_classification TYPE TABLE OF bapi1003_alloc_values, ls_classification TYPE bapi1003_alloc_values, lt_return TYPE TABLE OF bapiret2, ls_return TYPE bapiret2, lv_min_pack_qty TYPE bapi1003_alloc_values-value. “ 存储找到的特性值 PARAMETERS: p_matnr TYPE matnr OBLIGATORY. “ 选择屏幕输入物料号 START-OF-SELECTION. lv_matnr_ext p_matnr. “ 1. 关键步骤将外部物料号转换为内部格式 CALL FUNCTION ‘CONVERSION_EXIT_ALPHA_INPUT’ EXPORTING input lv_matnr_ext IMPORTING output lv_matnr_int. “ 注意这里转换后lv_matnr_int 已经是MARA表需要的内部格式了。 “ 另一种更严谨的做法是调用 MARA_SINGLE_READ但转换函数在大多数情况下足够。 “ 2. 准备输入参数 OBJECT CLEAR ls_object. ls_object-objek lv_matnr_int. “ 传入内部物料号 ls_object-obtab ‘MARA’. “ 对象是物料 ls_object-klart ‘001’. “ 类类型是物料类001 “ 如果你不确定类类型可以尝试留空 ls_object-klart ‘ ‘但可能影响性能。 “ 3. 清空输出内表 CLEAR: lt_classification, lt_return. “ 4. 调用核心函数 CALL FUNCTION ‘CLAF_CLASSIFICATION_OF_OBJECTS’ EXPORTING object ls_object language sy-langu “ 使用当前登录语言 key_date sy-datum “ 使用当前日期 IMPORTING classification lt_classification return lt_return. “ 5. 检查返回消息 READ TABLE lt_return INTO ls_return WITH KEY type ‘E’. “ 查找错误 IF sy-subrc 0. “ 存在错误比如对象未找到、未分类等 MESSAGE ls_return-message TYPE ‘I’ DISPLAY LIKE ‘E’. RETURN. ENDIF. “ 6. 处理获取到的分类数据 IF lt_classification IS NOT INITIAL. “ 6.1 示例查找特定特性 ‘MIN_PACK_QTY’ READ TABLE lt_classification INTO ls_classification WITH KEY charact ‘MIN_PACK_QTY’. IF sy-subrc 0. lv_min_pack_qty ls_classification-value. WRITE: / ‘物料’, p_matnr, ‘的最小包装量为:’, lv_min_pack_qty. ELSE. WRITE: / ‘未找到物料’, p_matnr, ‘的 MIN_PACK_QTY 特性。’. ENDIF. “ 6.2 示例循环输出所有特性用于调试或查看全貌 WRITE: / / ‘该物料的所有分类特性:’. LOOP AT lt_classification INTO ls_classification. WRITE: / ls_classification-charact, ‘:’, ls_classification-value, ‘(描述:’, ls_classification-value_descr, ‘)’. ENDLOOP. ELSE. WRITE: / ‘物料’, p_matnr, ‘没有分配任何分类数据。’. ENDIF.代码关键点解析第1步转换CONVERSION_EXIT_ALPHA_INPUT是必须的。SAP中物料号通常存储为18位字符内部格式用户输入的100-100和系统中存储的0000000000000100100是不同的。不进行转换OBJEK对不上函数会返回“对象未找到”的错误。第4步调用调用本身很简单。注意我们传递了language和key_date这确保了获取的是当前语言下、当前有效的分类数据。第5步检查这是一个非常重要的好习惯。即使函数执行成功SY-SUBRC 0RETURN表里也可能包含警告或信息类消息。例如对象没有分配任何类RETURN表里可能会有类型为‘I’的消息‘Object is not allocated to any class’。直接检查RETURN表比依赖SY-SUBRC更可靠。第6步处理CLASSIFICATION内表包含了所有数据。你可以通过CHARACT字段查找特定特性也可以通过CLASS字段按类来分组查看。VALUE字段是字符串对于数值型特性可能需要用MOVE或WRITE ... TO ...语句将其转换到数值变量中。4. 性能优化与批量查询技巧上面的例子是单对象查询。在实际开发中比如报表或增强程序里我们更常需要处理成百上千个物料。如果对每个物料都单独调用一次FM会产生巨大的RFC调用开销虽然这个FM是本地调用但依然有函数调用开销和重复的数据准备逻辑性能会非常差。正确的做法是使用OBJECT_TABLE参数进行批量查询。DATA: lt_object_table TYPE TABLE OF klah-objek_tab, ls_object_table TYPE klah-objek_tab. DATA: lt_matnr_list TYPE TABLE OF matnr. “ 假设这是你的物料清单 “ 假设 lt_matnr_list 已经填充了需要查询的物料号外部格式 LOOP AT lt_matnr_list INTO DATA(lv_matnr_ext). CLEAR ls_object_table. CALL FUNCTION ‘CONVERSION_EXIT_ALPHA_INPUT’ EXPORTING input lv_matnr_ext IMPORTING output ls_object_table-objek. ls_object_table-obtab ‘MARA’. ls_object_table-klart ‘001’. APPEND ls_object_table TO lt_object_table. ENDLOOP. “ 批量调用 IF lt_object_table IS NOT INITIAL. CALL FUNCTION ‘CLAF_CLASSIFICATION_OF_OBJECTS’ EXPORTING object_table lt_object_table language sy-langu key_date sy-datum IMPORTING classification lt_classification “ 现在这里包含所有物料的数据 return lt_return. ENDIF. “ 处理 lt_classification “ 此时 lt_classification 内表的行数 物料数 x 每个物料的特性数。 “ 你需要通过 OBJKEY 字段来区分不同物料的数据。 SORT lt_classification BY objkey charact. LOOP AT lt_classification INTO ls_classification. “ 根据 ls_classification-objkey 判断当前行属于哪个物料 “ ... ENDLOOP.批量查询的优势单次调用无论多少物料只发生一次函数调用。减少开销避免了循环中重复的参数准备、调用、返回检查等开销。数据库优化SAP底层在读取AUSP等表时可能会对IN条件进行优化比多次单个SELECT效率更高。注意批量查询时返回的CLASSIFICATION内表会非常大物料数 × 特性数。在处理时一定要先按OBJKEY对象键进行排序或建立循环分组否则数据会混杂在一起难以处理。同时要警惕内表过大导致的内存问题如果物料数量极多例如上万可能需要分批次处理。5. 常见“坑点”与排查指南即使知道了函数和用法在实际操作中依然会踩到一些坑。下面是我总结的几个典型问题和解决方法。5.1 坑点一OBJEK传错导致查不到数据这是最常见的问题。症状是函数执行成功SY-SUBRC 0RETURN表里没有错误但CLASSIFICATION内表为空RETURN表里可能有一条信息消息说对象未分配类。排查步骤确认对象是否存在首先确保你传入OBJEK的物料号在MARA表中确实存在。可以用SELECT SINGLE查一下MARA-MATNR。确认内部格式99%的问题出在这里。把你准备传入OBJEK的变量内容在调试器里或通过WRITE语句输出出来。看看它是不是像0000000000000100100这样的18位字符串而不是100-100。务必使用CONVERSION_EXIT_ALPHA_INPUT。确认对象类型和类类型OBTAB必须是‘MARA’。KLART可以尝试先留空‘ ‘看看是否能查到数据。如果能查到再根据查到的CLASSTYPE字段来确定正确的类类型。有时物料可能被分配到多个类类型下如001和200。5.2 坑点二特性值显示为代码而非描述你调用函数后发现VALUE字段里显示的是像‘RED’、‘HIGH’这样的代码而不是期望的‘红色’、‘高’这样的描述。原因与解决这是因为该特性配置了“值分配”Value Assignment即有一个代码表。在这种情况下VALUE_NEUTRAL字段存储的是代码如‘RED’。VALUE字段可能存储代码也可能存储描述这取决于特性的配置和函数的处理逻辑。VALUE_DESCR字段通常存储的是描述文本。所以正确的做法是优先使用VALUE_DESCR字段来获取用户友好的描述。如果VALUE_DESCR为空再回退到VALUE字段。同时VALUE_NEUTRAL可以作为内部处理的键值使用。5.3 坑点三区间值Interval特性的处理有些特性是区间类型的比如“长度范围”定义为10 – 20 CM。对于这种特性DATA_TYPE可能是‘NUM’或‘CHAR’但会伴随FROM和TO字段被填充。VALUE字段可能显示为‘10 - 20’这样的字符串也可能为空。FROM字段存储区间下限‘10’。TO字段存储区间上限‘20’。在程序逻辑中判断一个值是否落在某个物料的特性区间内时需要同时判断FROM和TO。如果FROM和TO都为空则看VALUE。5.4 坑点四多值特性Multiple Values的处理一个特性如果允许多个值在分类配置中勾选了“多值”那么同一个CHARACT会在CLASSIFICATION内表中出现多行每一行代表一个分配的值。你的循环处理逻辑需要能够汇总或处理这些多值。例如特性“适用季节”可能同时有“春”和“秋”两个值。5.5 性能陷阱在循环中嵌套调用这是最需要避免的架构问题。永远不要在LOOP AT itab的内部去调用CLAF_CLASSIFICATION_OF_OBJECTS单对象模式。如前所述这会产生 N 次函数调用。务必使用OBJECT_TABLE参数进行批量查询。如果源数据量巨大设计一个分页或分批处理的逻辑。6. 进阶应用与其他BAPI/函数的协同CLAF_CLASSIFICATION_OF_OBJECTS通常不是孤立使用的它常作为数据获取链条中的一环。场景一在BAPI物料创建/修改后获取分类当你使用BAPI_MATERIAL_SAVEDATA创建或修改物料并同时通过BAPI_OBJCL_CREATE或BAPI_OBJCL_CHANGE分配了分类后你可以立即调用CLAF_CLASSIFICATION_OF_OBJECTS来验证分类数据是否已成功更新到数据库。注意BAPI调用后需要执行COMMIT WORK或BAPI_TRANSACTION_COMMIT数据才会真正写入AUSP等表之后才能被查询到。场景二与物料查询BAPI结合BAPI_MATERIAL_GETLIST或BAPI_MATERIAL_GET_DETAIL可以获取物料的基本信息。如果你需要的是一个同时包含基本数据和分类数据的物料清单通常的流程是调用BAPI_MATERIAL_GETLIST获取物料号列表。将这些物料号转换为内部格式填入OBJECT_TABLE。调用CLAF_CLASSIFICATION_OF_OBJECTS批量获取所有分类数据。在程序内将两个结果集基本数据列表和分类数据列表通过物料号MATNR/OBJKEY关联起来。场景三在增强或出口中快速获取特性在用户出口如MV45AFZZ、BADI实现如MATERIAL_UPDATE或自定义增强中当系统传递给你一个物料号时你可能需要根据它的某个特性值来决定业务逻辑。此时在增强点内调用CLAF_CLASSIFICATION_OF_OBJECTS是一种干净利落的做法。但需注意性能如果该增强点本身就在一个循环中被频繁调用你需要评估是否改为在更早的节点批量获取数据。7. 替代方案浅析何时不用这个FM虽然CLAF_CLASSIFICATION_OF_OBJECTS很强大但也不是万能的。在某些特定场景下可能有更优的选择。超高性能要求下的简单查询如果你仅仅需要查询一个物料在某一个特定类下的某一个特定特性的值并且这个调用发生在性能极其敏感的环节如每行交货单的定价增强那么直接写SQL查询AUSP表可能更快。前提是你非常清楚AUSP与KSSK等表的关联关系OBJEK 对象内部号 KLART 类类型通过KSSK找到CLINT再用CLINT和ATINN去AUSP里找ATWRT。这种方式牺牲了可读性和维护性换取了极致的性能需谨慎使用。使用CDS视图在S/4 HANA环境中SAP提供了一些预定义的CDS视图来暴露分类数据例如I_ClassificationInternalAssignment等。在ABAP云环境或新的Fiori应用开发中使用CDS视图是更推荐的方式。但对于传统的ABAP报表或ECC系统中的增强FM仍然是主流。类特有的函数对于一些标准的类类型SAP也提供了更专用的函数。例如对于批次特性有函数BAPI_OBJCL_GETDETAIL和BAPI_BATCH_GET_DETAIL后者也能返回批次特性。这些函数接口可能更简单但通用性不如CLAF_CLASSIFICATION_OF_OBJECTS。选择建议对于绝大多数自定义开发、报表和增强场景CLAF_CLASSIFICATION_OF_OBJECTS因其接口清晰、功能全面、官方支持仍然是首选方案。只有在经过严格性能测试证明其成为瓶颈且查询模式极其固定的情况下才考虑直接操作底表。回过头看最初我同事面对的那个复杂SQL其实完全可以用十几行清晰的ABAP代码替代核心就是对这个FM的正确调用。它封装了SAP分类系统底层复杂的表关联提供了一个稳定、可靠的查询入口。掌握它意味着你在处理SAP中任何与“特性”相关的需求时都有了得心应手的工具。下次当你需要从物料、设备或任何SAP对象中提取那些“隐藏”在分类里的属性时不妨先想想这个FM它很可能就是通往答案最直的那条路。
返回列表