ARTICLE DETAIL

资讯详情

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

SAP SM30从入门到进阶:条件筛选与动态校验实战技巧

SAP SM30从入门到进阶:条件筛选与动态校验实战技巧 做SAP运维和实施的兄弟对SM30这事务代码肯定不会陌生。别看它界面简单就是个能增删改查表数据的维护工具但真到上线支持阶段你会发现这个“简单工具”藏着不少门道。我见过太多人用SM30就是进去找条记录、改个值、保存走人一旦遇到表数据量大、校验逻辑复杂、多人并发维护的场景立马卡壳。今天这篇不讲那些虚头巴脑的SAP理念就结合我自己项目里的实际经验把SM30从“能用”用到“好用”的关键技巧掰开揉碎聊一聊重点放在条件筛选和动态校验这两块硬骨头上。这篇内容适合正在做SAP实施、运维支持的顾问尤其是MM、SD、FICO模块的配置顾问——因为你们八成每天都在跟SM30打交道。哪怕你是刚入门的技术顾问只要会一点ABAP基础这里面的逻辑和代码思路也能直接帮你解决不少实际问题。1. 别再把SM30当“高级SE16”用了很多人第一次接触SM30感觉它就是个维护数据库表的工具跟SE16查数据差不多只不过能改数据而已。这个理解不算错但严重低估了SM30作为一个“表维护生成器”的能力边界。1.1 表维护生成器到底是什么SAP里并不是所有表都能直接进SM30维护。你得先在SE11里对表执行“生成表维护程序”之后SM30才能识别这张表并允许你维护。这一步很多人建表时都跳过或者忘了等项目上线了业务顾问跑过来说“这表我用SM30进不去”就得灰溜溜回去补生成。表维护生成器生成的东西实际上是一个模块池或函数组里面包含了标准的增删改查逻辑、屏幕逻辑、事件处理框架。你可以通过SE11菜单“环境→表维护生成器”进去也可以直接在SE93里维护事务代码把生成的程序挂给一个自定义事务码。这一步的核心意义在于SM30只是调用这个生成的维护程序并不是像SE16那种直读底层数据库表。这里就引出一个关键概念SM30的维护逻辑是可以被“植入”自定义代码的。也就是说你在SM30界面点保存时执行的不只是简单的UPDATE语句而是可以经过一系列校验、增强、前后端交互后再写进数据库。明白了这一点后面讲动态校验你才能真正理解它的威力。1.2 直维护与SM30维护的区别顺便提一嘴还有个东西叫“直维护表”直接定义维护属性的表DD02L里输个Y就能直接SE16N维护。这种方式只适合极简单的配置表我强烈不建议在项目里用直维护。直维护没有事件校验、没有屏幕逻辑、没有权限检查就跟裸奔一样业务人员误操作一次数据就废了。SM30虽然要额外生成维护程序看起来多了一步但它带来的东西值得标准的权限对象支持、屏幕字段控制、事件校验钩子、多行数据批量操作。所以只要是需要业务人员或顾问长期维护的数据尽量都走SM30不要图省事去搞直维护。2. 条件筛选提速从数据海洋里精准捞针配置表的数据量通常不算大但也有例外。我在项目上遇到过物料主数据相关的一些自定义表几十万条记录也是常事。在这种表上用SM30默认的查询逻辑能急死人。所以先聊筛选筛选做不好后续动态校验再强也无从谈起。2.1 视图变式View Variant是标配SM30的查询界面左下角有一个“视图变式”功能很多人没注意过。它的作用就是把你常用的一组筛选条件保存下来下次进来一键带入。比如我维护一张工厂相关的配置表经常需要按“工厂1000 物料类型ROH”来查那就在布局里设置好条件后存成变式下次点一下变式图标筛选条件全自动带上。这个功能看似简单但实际能极大减少重复输入。尤其是在支持阶段业务顾问频繁打电话问你“帮我看看XXX配了没”你每次都要输一遍筛选条件真的很烦。用变式保存好你常用的几组查询场景工作效率能提升一个档次。2.2 范围维护功能的巧用SM30列表界面有一个“范围维护”功能在菜单栏“设置→范围维护”里。它的作用是先把查询结果集锁定在某个ID范围内然后在这个范围内继续做增删改操作。这个功能对那种一次要维护一批相似数据的场景特别有用。举个例子你在维护一张定价条件表需要把某个价格区间内的所有记录都改一个字段值。如果不用范围维护你可能要反复查询多次。用范围维护锁定好范围后直接在这个范围内逐条翻记录、改数据保存一次搞定。这里面有个细节范围维护的“范围”是内存级别的也就是说你切走事务代码范围就没了所以该保存时就保存别屯一堆操作在内存里。2.3 别忽视SQL跟踪的辅助作用如果一张表在SM30里查询速度慢别光在那里等也别骂系统慢先用ST05跟踪一下后台到底执行了什么SQL。SM30的标准查询逻辑是按照表的关键字段做等值匹配。如果你的筛选条件用上了非索引字段后台就会走全表扫描数据量大自然慢。我遇到过一次查询巨慢的情况原因就是用户在筛选条件里填了一个非关键字段的模糊匹配值。这种查询在底层会比等值查询慢得多。解决办法要么是引导用户换用关键字段筛选要么是在表的数据库索引上做文章——加个二级索引。SAP的配置表一般不允许随便加索引这会牵扯到升级和传输问题所以最靠谱的方案还是在事件里写自定义的筛选逻辑让查询条件走索引效率高。2.4 事件里写动态WHERE条件说到事件筛选这块就能先尝到点甜头。表维护生成器在事件05和事件01里可以通过系统结构“VIM_..._WHERE”之类的参数拼接WHERE条件部分场景下还能干更复杂的事。但说实话SM30标准的筛选机制已经够用大多数情况下你不需要去写动态WHERE——真正麻烦的是筛选出来之后的逻辑判断这就引出动态校验了。3. 动态校验的实现SM30事件流的实战应用动态校验是SM30最值钱的功能没有之一。表维护生成器提供了五个标准事件分别是事件触发时机关键字05创建新条目前新建前校验适合赋默认值01数据修改前增改删除都已存在行修改前校验适合更新时拦截03删除前删除特有逻辑校验02保存前即将写库前统一校验04保存后保存成功后的后续处理这些事件对应的FORM子程序名字是固定的比如事件05对应FORMBUILD_..._INITIAL_VALUES事件01对应FORMCHECK_..._DATA、事件02对应FORMSAVE_..._DATA、事件03对应FORMDELETE_..._DATA。你在表维护生成器里填写事件编号和程序名后代码就会在这些时机点被执行。3.1 事件05新条目默认值注入事件05是在你点击“新建条目”后、屏幕输入框出现前触发的。这地方最典型的应用是给字段自动赋值。比如你有一张“销售组织-分销渠道-语言”配置表希望每次新建条目时语言自动填充成中文ZH销售组织自动带出当前用户默认的销售组织那你就在事件05里写FORM build_zcustom_config_initial_values. DATA: ls_maint_view TYPE zcustom_config. FIELD-SYMBOLS: fs_maint_view TYPE zcustom_config. ASSIGN total TO fs_maint_view CASTING. IF fs_maint_view IS ASSIGNED. IF fs_maint_view-spras IS INITIAL. fs_maint_view-spras ZH. ENDIF. IF fs_maint_view-vkorg IS INITIAL. fs_maint_view-vkorg 1000. ENDIF. ENDIF. ENDFORM.这里面有一个非常关键的ABAP细节通过ASSIGN total TO fs_maint_view CASTING来访问当前维护行的数据。total是表维护程序的标准结构很多人写事件老是取不到当前行的值多半就是没用这个系统结构做CASTING。事件01和事件03里这个结构同样通用用法一致。3.2 事件01修改前的字段一致性校验事件01是你改了数据、从当前行离开时触发的非常适合做字段间的联动校验和跨表校验。举个最常见的业务场景你有一张物料状态配置表选了“冻结”状态就必须填写“冻结日期”选了“释放”状态“冻结日期”就得清空同时如果填写的工厂在T001W里不存在直接报错。FORM check_zcustom_config. DATA: lv_count TYPE i, lv_msg TYPE string. FIELD-SYMBOLS: fs_maint_view TYPE zcustom_config. ASSIGN total TO fs_maint_view CASTING. 状态和日期的联动校验 IF fs_maint_view-status FREEZE AND fs_maint_view-frozen_date IS INITIAL. MESSAGE e001(zcustom_messages) WITH 冻结状态下必须维护冻结日期. ENDIF. IF fs_maint_view-status RELEASE. CLEAR fs_maint_view-frozen_date. ENDIF. 跨表校验工厂是否存在 SELECT COUNT(*) FROM t001w WHERE werks fs_maint_view-werks. IF sy-subrc 0. MESSAGE e002(zcustom_messages) WITH fs_maint_view-werks. ENDIF. ENDFORM.注意值过滤用SELECT COUNT(*)而不是SELECT SINGLE是因为在事件里频繁调用数据库查询如果表数据量大COUNT(*)配合主键条件其实并不慢而且代码可读性更高。但如果你要校验的是MARA这种主数据大表建议直接用SELECT SINGLE查关键字段后判断SY-SUBRC能省一点是一点。3.3 MESSAGE类型的选择是门学问在动态校验里MESSAGE语句的消息类型严重影响着用户体验。这个细节我特别想强调一下如果你用E类型错误系统会强制终止当前操作弹出红色的错误提示用户必须点击Enter或直接取消交互成本很高。如果你用S类型成功、W类型警告用户点击Enter后可以通过。什么场景用哪种消息类型建议按照下面的表来场景消息类型原因用户填写了非法值E错误必须阻止继续操作可以自动修复的异常W警告提示用户注意但允许继续跨表校验通过S成功一般不需要弹少数场景提示数据即将产生重大影响W警告Enter给用户一个确认过程我踩过的坑是刚开始在事件里全用E类型结果业务人员填错一个字段就要弹好几次错误框烦得不行。后来改成能自动修复的自动修复比如状态变了就自动清空日期只是在里层用W类型提示一句体验一下子好了。SAP顾问的活儿不是把逻辑写对就行用户体验同样重要否则业务人员天天骂系统“难用”背锅的还是我们。3.4 事件02保存前的批量校验与数据加工事件02跟事件01的最大区别是事件01是行级校验你离开哪行就校验哪行事件02是整体校验发生在所有行都改完、你点保存的那一瞬间此时校验的是整个内表的数据。这就意味着事件02能做跨行校验、全表重复性检查以及批量数据加工。我做过一个项目有一张库存地点的自定义配置表要求“工厂库存地点”在全表里不允许重复。如果你把重复检查放在事件01里你会发现根本无法实现因为事件01只能看到当前行看不到全局。放事件02里就顺理成章了在保存前把整个内表LOOP一遍用内表的标准表排序去重逻辑判断重复。FORM save_zcustom_config. DATA: lt_data TYPE TABLE OF zcustom_config, ls_data TYPE zcustom_config. FIELD-SYMBOLS: fs_maint_view TYPE zcustom_config. 从TOTAL里取出所有行 LOOP AT total ASSIGNING fs_maint_view CASTING. MOVE-CORRESPONDING fs_maint_view TO ls_data. APPEND ls_data TO lt_data. ENDLOOP. SORT lt_data BY werks lgort. LOOP AT lt_data INTO ls_data. AT NEW werks. 每个工厂内再检查库存地点重复 ENDAT. READ TABLE lt_data WITH KEY werks ls_data-werks lgort ls_data-lgort TRANSPORTING NO FIELDS BINARY SEARCH. ENDLOOP. ENDFORM.这个逻辑其实还有更简洁的写法比如用DELETE ADJACENT DUPLICATES配合行数对比。不过上面这段已经把核心思路表达清楚了你需要理解的是事件02里你面对的是一个完整数据集什么跨行逻辑都能写。这里再补充一点保存前的校验如果发现错误可以MESSAGE E...直接阻止本次保存的所有数据入库不会出现“改了一半、另外一半进了库”这种半拉子状态。3.5 自定义事件扩展SM30的隐藏能力除了那五个标准事件表维护生成器还允许你自己定义事件编号比如10、11等然后在某个标准时机用CALL CUSTOMER-FUNCTION调用。这是在标准事件无法满足需求时的终极手段。比如我在一个项目里做过一个需求用户在SM30里维护数据时希望每次修改都要填写“修改备注”这个备注不存进配置表本身而是写进一张自定义的日志表。实现思路就是自定义一个事件10在事件01里调用它把当前用户、修改时间、修改内容写进日志。代码大概长这样FORM customer_function_010. DATA: ls_log TYPE zcustom_change_log. FIELD-SYMBOLS: fs_maint_view TYPE zcustom_config. ASSIGN total TO fs_maint_view CASTING. MOVE-CORRESPONDING fs_maint_view TO ls_log. ls_log-uname sy-uname. ls_log-datum sy-datum. ls_log-uzeit sy-uzeit. ls_log-change_type MOD. INSERT zcustom_change_log FROM ls_log. ENDFORM.自定义事件的启动时机完全由你控制你可以在标准事件里通过CALL CUSTOMER-FUNCTION 010来调用它。这种用法灵活很多但也要求你对整个维护流程的理解更深入。初学者建议先把标准事件吃透自定义事件等有需求了再上。4. 多人并发维护的锁与冲突问题SM30多个人同时维护一张表这是上线支持阶段的高频场景。SAP的锁机制天然支持SM30的排他锁但你如果没搞懂锁的粒度照样会踩坑。4.1 SM30的锁粒度是按表还是按行SM30默认锁定的是整张表也就是说你进入一张表的维护界面后系统会尝试对你的用户名加一个表级排他锁与此同时其他用户再想进这张表维护会提示“对象被XXX锁定”等待或者直接进不来。这对配置操作来说好处是避免了两个人同时改同一张表的冲突坏处是——效率太低。项目上的配置顾问一般不止一个不同的顾问可能负责不同的工厂他们都不想因为同事在维护同一张表就被锁在外面。这时候解决方案是在表维护生成器的“锁定模式”里选择“可设置锁定模式”而不是“标准锁定”。设置之后用户进入维护界面时可以选择锁定方式是锁定整张表还是按关键字段值精确锁定到行级。这个设置对那种“工厂配置项”结构的大配置表特别有用。4.2 锁冲突的实战处理流程真遇到锁冲突了不要急处理流程一般是先看冲突提示里的用户名是谁。用事务码SM12查看这个用户到底锁定了什么对象。确认对方是否真的在维护这张表还是锁残留了比如用户中途崩溃或者网络断开锁没被释放。如果确认是残留锁直接跟对方确认后删锁即可如果不是残留锁就等对方保存退出。这里强调一点删锁是最后手段不要动不动就去SM12里删别人的锁。删锁可能导致对方后续保存时出现数据不一致的奇怪错误到时候排查起来更痛苦。4.3 VIM锁定与自定义增强的坑还有一个非常容易踩的坑自定义事件代码里如果执行了UPDATE语句一定要考虑你自己的更新对表锁的影响。比如上面那个写日志表的例子你往日志表INSERT数据系统会尝试对日志表加锁。如果日志表恰好被别人占用你的保存就会失败连带配置表的数据也保存不了。解决办法是把日志写入这类操作放在事件04保存后里执行因为事件04触发时主表的锁已经拿住了你再去INSERT日志表即使日志表锁冲突也只会导致事件04报错影响范围要小得多。更稳妥的办法是使用COMMIT WORK AND WAIT主动提交日志写入的数据库操作把日志写入的事务独立开。5. 常见问题与排错速查实录下面这些坑是我自己在项目里和论坛上反复看到的整理成速查表你们直接照着排查就行。现象可能原因排查思路SM30里看不到某张表没生成表维护程序SE11查表环境→表维护生成器重新生成保存时提示“无权限”权限对象S_TABU_DIS没分配PFCG里加权限对象检查活动权限事件代码不生效表维护程序没激活或增强ID没保存SE11检查表维护程序生成状态重新生成新建条目保存后某字段丢失字段没被设为“维护属性”SE11表维护生成器里勾选字段的输入/输出状态保存慢事件02里写了大量SELECT优化事件代码把跨表查询改为内表关联进来修改时报“对象被锁定”锁残留或他人正在维护SM12查锁判断后处理用非关键字段筛选超慢查询走了全表扫描换用关键字段筛选或加数据库索引修改数据时提示“字段XXXX不能修改”该字段在维护程序里被设为显示字段更新表维护程序的屏幕布局把字段改为可输入这里单独说一下“保存时提示无权限”这个情况。SAP的表维护权限由权限对象S_TABU_DIS控制不是简单的给表名就行。你需要关注三个点表组表组权限、授权组权限组、活动类型01维护、03显示等。很多权限问题都是权限组没对上的原因跟表名其实没直接关系。配置权限时建议按模板拷贝再改名不要从零去手工填权限值容易漏。6. 最后再分享几个实操细节聊到最后我再分享几个平时文档里不容易找到的小技巧。第一个是关于字段默认值的事件05里赋默认值别用MOVE直接赋值哪怕当前行字段有值也会被覆盖。如果你希望“有值就不动、没值才填充”一定先判断IS INITIAL再赋值这个判断逻辑我前面示例里已经写出来了。第二个是关于传输请求的。SM30维护的数据最好也在表维护生成器里勾选“维护时自动生成请求号”这样每次修改数据都会自动生成一个传输请求方便后续传输到测试机和生产机。这个功能默认不一定开但你作为顾问应该养成习惯别在开发机上改完配置却忘了记录它属于哪个请求到传输的时候再临时找人导出非常被动。第三个是关于SM30历史版本的。SM30本身不提供数据历史版本查询功能。如果你维护的配置表涉及重要的业务数据建议通过自己开发日志表或者用SAP的审计功能比如表更改日志来追踪变更。这个我在前面自定义事件的例子里已经交代了做法路径成本不高收益很大上线支持阶段能省掉一堆“这个数据是谁改的、什么时候改的”这种扯皮问题。SM30这套东西说到底是SAP配置维护体系的基石之一。它不复杂但深度足够。把条件筛选和动态校验掌握好绝大部分自定义配置表的维护需求你都能应付。遇到更复杂的场景记住一条准则任何标准功能满足不了的需求先想SM30的事件再想增强最后才想替代方案——顺序别搞反了。
返回列表