ARTICLE DETAIL

资讯详情

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

金蝶ERP基础档案数据字典:SQL查询、去重与维护实操

金蝶ERP基础档案数据字典:SQL查询、去重与维护实操 做金蝶运维和二次开发的朋友估计都有过这种时刻领导丢给你一个Excel模板让你把系统里所有客户资料导出来或者财务要核对科目余额但界面里一条一条翻要翻到天亮又或者某个物料明明显示停用可单据里还是能选到。这些问题的共同解法就是直接进数据库写SQL。写SQL的第一步不是背语法而是先搞懂金蝶基础档案在数据字典里的样子。我整理这篇东西主要围绕金蝶基础档案数据字典的SQL语句展开覆盖K3 Wise和云星空两代常见产品把表和字段的分布逻辑、能直接抄的查询语句、字段含义反查方法以及我实际维护过程中踩过的重复数据和状态位坑都说一遍。适合做金蝶实施、运维、二次开发或者需要在账套底层直接取数核对的朋友参考。金蝶不同版本、不同补丁的表结构会有差异但查询和联表的思路是通用的这一点搞明白了换套账套也能很快上手。1. 基础档案在数据库里的“家”从 t_Item 到 T_BAS 系列很多人拿到金蝶数据库第一件事就是打开企业管理器看表名。一眼扫过去几百张表t_开头、T_BD_开头、T_BAS_开头根本分不清哪张是存物料、哪张是存客户的。我刚开始做K3项目时也这样后来才明白金蝶基础档案的表结构虽然乱但内核逻辑是固定的。1.1 K3体系里基础资料共用一张主表K3 Wise以及更早的K/3系列几乎所有的“基础资料”都会在t_Item这张表里登记一笔记录。部门、职员、客户、供应商、物料、仓库甚至会计科目的部分信息都能在t_Item里找到影子。t_Item的核心字段就那几个FItemID内部主键所有关联表都用它来挂钩。FItemClassID表示这条记录属于哪一类基础资料。FNumber编码。FName名称。FFullName全名通常带上级路径。FDeleted假删除标志0为有效1为已删除。关键就在FItemClassID。它是连接到t_ItemClass表的外键t_ItemClass里定义了账套中有哪些基础资料类别。所以查K3基础档案时我不会上来就写WHERE FItemClassID 某某编号因为这个编号每个账套不一定一样而且不同版本预设顺序可能有变化。更稳妥的做法是先看类别表SELECT FItemClassID, FItemClassName FROM t_ItemClass ORDER BY FItemClassID;跑完你就知道当前账套里客户、供应商、物料、部门分别对应哪个ID。然后再拿着这个ID去查t_Item这样基本不会串。不过要注意t_Item只是存了最通用的编码、名称这些字段。像物料的规格型号、计量单位客户的应收应付科目设置这些个性化字段不在t_Item里而是放在各自的业务扩展表中。K3里比较常见的是物料用t_ICItem或ICItem视图客户有t_Customer供应商有t_Supplier科目是t_Account。理解这张主表和扩展表的关系比死记硬背表名更靠谱。1.2 云星空把表拆得更细了金蝶云星空包括现在的苍穹底层在表结构上比K3规范得多但也更容易让习惯K3的人不适应。星空里基础资料不再是“全部塞进一张t_Item”而是每个业务对象一张主表多语言字段再单独拆一张_L结尾的扩展表。例如物料主数据T_BAS_MATERIAL扩展表T_BAS_MATERIAL_L客户T_BD_CUSTOMER扩展表T_BD_CUSTOMER_L供应商T_BD_SUPPLIER扩展表T_BD_SUPPLIER_L部门T_BD_DEPARTMENT组织T_ORG_ORGANIZATIONS主表里放的是内部ID、编码、状态、组织隔离等通用字段_L表放的是名称、备注这类跟语言和文化相关的字段。为什么这么设计因为云星空要考虑多语言账套一种名称在简体、繁体、英文下可能不一样单独拆表可以避免主表每个字段都做多语言支持。这个思路从查询角度理解很简单你要查物料的名称就得把主表和_L表关联起来。所以在写博文或记笔记的时候我的建议是不要只记表名要记“基础资料的通用查询套路”。K3看t_Item加扩展表星空看业务主表加_L语言表这个思路能帮你省掉大量翻表的时间。2. 拿来就能用的基础档案查询SQL从单表到多表关联接下来进入正题写一些我实际项目里经常用的查询SQL。这些语句不是教科书写法而是我在交付项目、对账、清洗数据时反复验证过的版本直接复制到SQL Server Management Studio里改一下账套名称和筛选条件就能跑。2.1 查物料档案K3和星空各来一段K3里查物料我最常用的语句长这样SELECT i.FNumber AS 物料编码, i.FName AS 物料名称, ic.FModel AS 规格型号, ic.FUnitID AS 基本单位内码 FROM t_ICItem ic INNER JOIN t_Item i ON ic.FItemID i.FItemID WHERE i.FDeleted 0 AND i.FNumber LIKE RM% ORDER BY i.FNumber;这里为什么用INNER JOIN而不是直接查t_ICItem因为在K3体系里t_ICItem的物料明细数据和t_Item的公共数据是分开维护的两者需要靠FItemID对上。如果你只查t_ICItem可能漏掉名称只查t_Item就会没有规格型号。云星空里写法会更“正规”一些SELECT m.FNUMBER AS 物料编码, ml.FNAME AS 物料名称, m.FSPECIFICATION AS 规格型号 FROM T_BAS_MATERIAL m LEFT JOIN T_BAS_MATERIAL_L ml ON m.MATERIALID ml.MATERIALID WHERE ml.FLOCALEID 2052 AND m.FISDELETE 0 ORDER BY m.FNUMBER;FLOCALEID 2052表示简体中文环境如果你的账套是英文界面这个值就不一样。这个字段很容易被忽略不写它多语言环境下名称会重复显示排查起来很头疼。2.2 客户、供应商、部门和科目的查询套路客户和供应商在K3里跟物料类似也是“公共表扩展表”的模式。查客户SELECT i.FNumber AS 客户编码, i.FName AS 客户名称, i.FFullName AS 客户全名, c.FShortName AS 简称, c.FContact AS 联系人 FROM t_Item i LEFT JOIN t_Customer c ON i.FItemID c.FItemID WHERE i.FItemClassID (SELECT FItemClassID FROM t_ItemClass WHERE FItemClassName LIKE %客户%) AND i.FDeleted 0;这段SQL用子查询先取客户类别的ID好处是换账套不用改死值直接复制过去就能跑。缺点是多一次子查询但性能上完全够用。供应商就把t_Customer换成t_Supplier类别筛选条件改成“供应商”其余套路一模一样。如果你需要带出客户对应的默认结算方式、币别或者供应商的应付科目再去t_ItemDetail或者各自的扩展表里多关联几个字段即可。部门在K3里往往也是t_Item的一个类别。查部门清单SELECT FNumber, FName, FFullName FROM t_Item WHERE FItemClassID (SELECT FItemClassID FROM t_ItemClass WHERE FItemClassName LIKE %部门%) AND FDeleted 0;科目表的差异比较大。K3的会计科目在t_Account和t_AccountDetail里和t_Item的关系不是简单的扩展表关系。查科目最直接的就是SELECT a.FNumber AS 科目编码, a.FName AS 科目名称, d.FFullName AS 科目全名 FROM t_Account a LEFT JOIN t_AccountDetail d ON a.FAcctID d.FAcctID WHERE d.FDeleted 0 ORDER BY a.FNumber;云星空里科目是在T_BAS_ACCOUNT类似命名的表里查法也是主表加语言表思路不变。2.3 组合条件查询的思路真正到项目里没人会只查“全部客户”更多是按条件过滤已停用的不要、某个业务组的只要、或者名称包含“华东”的筛出来。组合条件查询最容易犯的错是把业务字段的过滤条件写在了WHERE里但业务字段来自扩展表而扩展表可能没有匹配记录一INNER JOIN就把数据搞少了。我习惯这样处理先用LEFT JOIN把主表和扩展表都关联上再在WHERE里加条件这样即使扩展表某些字段为空基础记录也不会丢。例如SELECT i.FNumber, i.FName, c.FShortName, c.FAuditDate FROM t_Item i LEFT JOIN t_Customer c ON i.FItemID c.FItemID WHERE i.FItemClassID (SELECT FItemClassID FROM t_ItemClass WHERE FItemClassName LIKE %客户%) AND i.FDeleted 0 AND (c.FShortName IS NULL OR c.FShortName LIKE %华%);注意看这里FShortName为空也保留说明筛选条件用的是“IS NULL OR LIKE”的方式。很多新手直接写AND c.FShortName LIKE %华%结果导致没有简短的客户全部被过滤掉了数据对不上。3. 数据字典反查字段含义拿不准时的定位方法金蝶的基础档案字段少说也有几百个FAssistantObjType、FMaterGroup、FSupplyOrg光看英文缩写根本猜不出含义。这时候就体现出“数据字典”的价值了。但问题是很多实施项目交到我手里的时候根本没有一份现成的数据字典文档只能自己反查。我把常用的三种反查方法写出来。3.1 用SQL Server系统视图查表和字段SQL Server自带的sys.tables、sys.columns、sys.extended_properties这三张系统视图是我反查字段的起点。金蝶很多表和字段带了描述信息存在扩展属性MS_Description里。可以用下面这段SQL把某张表的字段描述全捞出来SELECT t.name AS 表名, c.name AS 字段名, ep.value AS 字段说明 FROM sys.tables t INNER JOIN sys.columns c ON t.object_id c.object_id LEFT JOIN sys.extended_properties ep ON ep.major_id t.object_id AND ep.minor_id c.object_id WHERE t.name LIKE %ICItem% AND ep.name MS_Description ORDER BY c.column_id;把%ICItem%换成你关心的表关键字就行。能查出描述当然好但也要有心理准备很多账套在建立时根本没维护扩展属性结果全是NULL。这时候就得靠第二种方法。3.2 从界面字段反推数据库列没有现成描述的时候我的做法是“界面输入数据库观察”。具体来说就是在金蝶客户端的某个单据或基础资料界面往一个文本框里输入一串特殊编码比如ZZTEST123保存后去数据库里查这条记录看哪个字段的值变成了ZZTEST123再结合界面上的标签文字判断字段含义。这个方法操作起来很朴素但对K3这种老系统特别管用。因为K3的界面字段和数据表字段往往不是同名映射直接猜英文缩写成功率很低。通过“录入特征值再查库”的方式基本能确定业务含义。唯一的成本就是你需要有测试账套的权限别在生产账套里乱试。3.3 自己维护一张字段速查表反查出来的字段含义如果只在脑子里记那过三个月一定忘。我从第二个项目开始就给每个账套单独建了一张Excel速查表列名就是这些表名、字段名、字段含义、来源界面、是否可修改、常见取值。每次在项目里新发现一个有价值的字段就随手记进去。积累两三个账套之后这张表就成了我自己的“金蝶数据字典”写SQL的效率高了一倍不止。说到底数据字典这东西别人给的是参考自己反查出来并验证过的才是真正能用的。如果你到了一个新单位没有现成字典强烈建议抽半天时间把常用基础档案表的字段描述导出来再花半小时界面反查补全把这个基础打好后面所有SQL操作都会顺利很多。4. 查询结果里的脏数据重复记录与去重SQL实战做过金蝶数据清洗的都知道基础档案最大的问题不是查不到而是查出来一堆重复。同一个客户编码出现两行同一个物料名称对应多个编码报表统计一下子就乱了。这一节我把重复数据的常见来源和去重SQL写法展开讲。4.1 重复记录是从哪来的重复记录的出现原因我总结了三个一是系统间导入。项目上线时从旧ERP批量导入基础档案导入模板没做唯一性校验同一个客户导了两次。二是多账套合并。集团合并分公司账套时各子公司对同一家客户分别建了档案编码规则不统一合并后自然重复。三是手工维护失误。操作员在界面上没有先检索看到不存在就直接新建结果同音字、大小写差异造成了重复。理解了来源才能选对去重策略。因为有的重复需要合并有的重复需要清理不能一概而论。4.2 四种去重SQL的写法与选择再说回SQL本身。金蝶基础档案去重通常围绕FNumber或FName来做分组。我常用的方法有四种各有适用场景。第一种最简单的是DISTINCT适合整行重复的场景。比如查询结果里因为多表关联产生了完全相同的行用DISTINCT直接去掉SELECT DISTINCT i.FNumber, i.FName, c.FShortName FROM t_Item i LEFT JOIN t_Customer c ON i.FItemID c.FItemID;但DISTINCT有个硬伤它没法告诉你“哪一条是真正要保留的”只是展示层面去重。如果你还需要把重复记录标出来或者保留一条就得用第二种方法ROW_NUMBER()窗口函数。;WITH DuplicateRows AS ( SELECT FNumber, ROW_NUMBER() OVER(PARTITION BY FNumber ORDER BY FItemID) AS Rn FROM t_Item WHERE FDeleted 0 ) SELECT FNumber, Rn FROM DuplicateRows WHERE Rn 1;这段SQL按FNumber分组FItemID越小排序越靠前序号为1的是保留项序号大于1的就是重复项。我们通常会保留FItemID最小那条理由是它往往是系统最早建立的原始记录后续重复建的可以直接停用或者假删除。第三种查重之后要“保留一条”并列出明细可以这样写SELECT i.FItemID, i.FNumber, i.FName FROM t_Item i INNER JOIN ( SELECT FNumber FROM t_Item WHERE FDeleted 0 GROUP BY FNumber HAVING COUNT(*) 1 ) d ON i.FNumber d.FNumber WHERE i.FDeleted 0 ORDER BY i.FNumber, i.FItemID;这种写法先把重复的编码找出来再关联回主表看具体明细适合人工核对“哪些需要保留、哪些需要清理”。第四种真正到清理阶段我不会直接写DELETE而是先更新一个临时标记位等业务确认后再操作。比如把重复记录的FDeleted先置为1。这个后面第五章会详细讲。4.3 查基础档案时不能只看一条记录还有一个小坑必须提醒金蝶很多表虽然有FDeleted字段但查询时如果忘了加过滤条件会把已删除的记录也带出来。已删除的记录在界面里看不到但数据库里还在统计数量时就容易虚高。另外状态位字段也很关键。有的表用FStatus表示审核状态有的用FForbid表示禁用状态还有的是FClosed。我在一个项目里就遇到过客户表里有个字段叫FServiceStop实际上表示的是业务停用状态功能和禁用差不多但名字完全不一样。这时候只能靠数据字典反查方法来确认千万别凭经验硬猜。5. 维护基础档案的SQL操作停用、改名、编码规则与状态位写SQL不只是为了查数有时候还得在数据库层面做维护。这一节聊几个我踩过坑的维护操作尤其是直接操作数据库时的边界和风险。5.1 批量停用不是直接 DELETE很多新手拿到重复数据清单第一反应就是写DELETE FROM t_Item WHERE ...这一删问题就大了。金蝶的基础档案和单据、凭证、BOM之间都是通过内码关联的直接删掉一行关联数据全部悬空界面打开报错成本计算错乱严重的直接毁账套。金蝶界面的“删除”按钮本质上也不是物理删除而是给FDeleted置1做假删除。所以数据库层面的批量停用我推荐的顺序是第一步备份表数据或者整个账套数据库 第二步用UPDATE把需要停用记录的FDeleted置1 第三步检查关联单据中是否还有引用如果有引用再通过业务系统里的禁用功能处理状态位。例如把指定客户类别下没有做过业务的重复客户假删除BEGIN TRAN; UPDATE i SET i.FDeleted 1 FROM t_Item i INNER JOIN t_Customer c ON i.FItemID c.FItemID WHERE i.FDeleted 0 AND i.FItemClassID (SELECT FItemClassID FROM t_ItemClass WHERE FItemClassName LIKE %客户%) AND i.FItemID NOT IN ( SELECT FItemID FROM t_SaleBill -- 假设销售订单引用客户内码 WHERE FItemID IS NOT NULL ); -- 确认无误后执行 COMMIT; -- 如果不对执行 ROLLBACK;注意前面的BEGIN TRAN;这是最保险的做法。我一般会在本地测试账套先跑一遍确认影响行数符合预期再在生产账套执行。生产操作是原则要么不执行要么必须留好回滚路径。5.2 改名与修改编码的边界基础档案的“名称”修改相对安全一些但也别有惯性思维。直接改某个扩展表里的名称字段有时界面刷新后能看到变了有时却还是旧名称因为金蝶有缓存机制。我的建议是小批量修改可以直改数据库但修改之后必须让用户刷新缓存或重启客户端大批量改名优先用金蝶自带的批量修改功能省得踩缓存坑。编码修改则要更加慎重。一个已经发生业务单据的物料或者客户编码一旦被别的表引用你在t_Item里把FNumber改了引用了这张表的视图和报表可能立即失效。金蝶在界面上会控制“已经发生业务的编码不可修改”但在数据库层面没有这层控制你改了也拦不住坏账就来了。所以涉及编码变更我的流程是先在业务系统看这个档案是否已有业务发生有的话用系统的变更单功能系统会自动处理关联引用确实要在数据库改的必须全局搜索这个FNumber在哪些业务表里出现逐一确认改动的波及范围。5.3 状态位字段的常见组合金蝶基础档案的状态位最常见的几个组合是FDeleted假删除标志。FStatus审核状态一般0为未审核1为已审核。FForbid禁用状态用于控制是否能被选择。FCancelled作废状态一般用于单据而非基础资料但有的版本基础资料也沿用。我见过项目里有人把“禁用”和“删除”混为一谈直接在界面上点禁用结果查不到数据其实只是因为状态位不对而已。理解这些标志位再去组合查询就顺手了。比如查出所有“未删除且已审核且未禁用”的物料SELECT FNumber, FName FROM t_ICItem WHERE FDeleted 0 AND FStatus 1 AND FForbid 0;如果不确定当前版本用的是哪个状态字段先查表结构再写条件。状态位字段搞错查出来的结果要么多要么少核对数据的结论就不可信了。6. 账套切换后的SQL差异与我的日常巡检习惯同一个操作在K3里能跑的SQL到云星空可能连表都不存在。这是很多从K3转到星空的人最先遇到的摩擦。我平时最怕的就是有人拿K3的t_ItemSQL直接往星空数据库里跑然后一脸问号说“现在金蝶到底怎么了”。这一节把差异和习惯都聊透。6.1 K3与云星空在基础档案查询上的主要差异我整理了一个对照表方便查阅对比维度K3 Wise金蝶云星空数据库类型基本固定为SQL Server支持SQL Server等多种数据库基础资料主表t_Item通用表 各扩展表各业务对象独立主表如T_BAS_MATERIAL名称存储t_Item的FName主表不存名称名称在_L语言扩展表删除标志常见FDeleted常见FISDELETE状态字段FStatus、FForbid等状态字段更规范但名称依然是英文缩写关联引用通过FItemID关联各表使用全局唯一内码字段名和含义差异明显这个表只是一个提纲挈领实际线上系统可能因为版本补丁不同而变化。但大方向是明确的K3偏向“一对公共主表承载所有基础资料”云星空偏向“每个业务对象独立表、独立字段”。写SQL前先判断产品再决定进哪套表比死记单条SQL更靠谱。6.2 日常巡检基础档案的三个习惯最后分享一下我个人在基础档案巡检上的几个习惯都是踩过坑之后养成的。一是每次写高危更新语句前先跑SELECT把影响行数查出来。影响行数的数量一旦和预期不符立刻停手不要抱着“先跑一下看看”的心态。二是善用事务回滚。SQL Server里的BEGIN TRAN和ROLLBACK组合我不会在生产上直接执行更新但我会把整个更新语句包在事务里先跑一遍检查结果再决定是提交还是回滚。上线这么多年这个习惯帮我把好几次濒临翻车的操作救了回来。三是给自己留一份账套级的数据字典。每接手一个新账套我会先用sys.tables把表结构导成Excel把常用基础档案的表名、关键字段、状态位含义补齐。这份东西平时放在项目共享盘里二次开发的时候大家都能用减少很多重复翻表的时间。金蝶的基础档案数据字典说复杂也复杂说简单也简单。复杂在于版本差异大、字段缩写多、表与表之间关系绕简单在于核心逻辑其实就几条先找对主表再关联扩展表别忽略状态位和删除标志写更新语句前一定留好回滚路径。把这些原则刻在脑子里再碰到任何一套金蝶账套你都能很快上手。
返回列表