CSV 父子层级模板(产品目录拆解)
PIM 或 BOM 导出文件写的是每一行的父级,所以它的箭头朝上;而连线到列写的是子级,所以箭头朝下。这份模板把这次反转画了出来:五级深度、五个判断、七个叶子节点。
什么是csv 父子层级模板(产品目录拆解)流程
产品目录导出文件和物料清单到来时是同一副样子。一行一个条目,一列 id,一列名称,还有一列写出这一行的父级——parent_id、parent_sku、belongs_to,写这份文件的系统碰巧叫它什么就是什么。层级全在里面。它只是以对画图来说方向相反的方式存着:每一行写出它上面的那一行,而任何地方都没有一行写出它下面的那些行。对数据库来说这是对的设计,因为一个单元格装一个值、从不装一个列表;对图表来说这是错的,因为一条箭头是从父级出发、抵达子级的。它也不是你搭出来的文件。CSV 是从系统里出来的东西,已经拍平了:没有留下公式替你重算那个查找,没有第二张工作表装着变体表,也没有颜色标注哪些行是成品。
QueryChart 的表格存的是相反的关系。连线到填这一行指向的那些行——它的子级——写成一串用逗号分隔的行号,连线文字按对应顺序填连线标签。所以这次转换就是一次反转,做一遍就好。把导出文件按父级列分组,每一组就成为它所指名的那一行的连线到值。一个有四个子级的父级,最后一个单元格里有四个数字;而每一个子级自己的连线到都是空的,它的位置被数进了父级的那一格里。父级单元格为空的行是根节点,而你希望它恰好只有一个:三个空父级就是三棵树,三棵树就是三张图。
有两点容易让人栽跟头。连线到装的是位置而不是标识符——它的值是这一行在表格里的编号,所以父级写着 SKU-1042 时,必须先解析成带这个编码的那一行的编号;而且插入一行会让它下面的一切重新编号。指向不存在的行的数字,会在画图时被丢弃,什么也不会告诉你。第二点是深度并不是一列:它要顺着父级链一路往上走、直到走到一个空值为止才能得到,这也是为什么同一种记录在同一份文件的不同分支里会处在不同的深度。下面这张图,就是一份小型户外家具目录严格照此画出来的样子——十九行横跨五个深度列和四条记录泳道,一个根节点、七个叶子节点,以及五个判断,落在目录真正分叉的那些地方:一个类目下面是否还要再嵌套、一个产品有没有变体行、一个条目是常备库存还是按单生产,以及一个组件是外购还是自制。
本流程图涵盖的内容
本模板包含
- 五个深度列——“根节点(父级为空)”和“深度 1”到“深度 4”——横跨四条记录泳道:“类目记录”“产品记录”“变体记录”和“组件记录”,于是导出文件的类型列变成页面上的一个位置,而父级链变成了列。
- 唯一的根节点“户外生活用品目录”,它在文件里是唯一父级单元格为空的那一行,向下分出两个深度 1 的类目“座椅”与“遮阳与遮蔽”。
- 深度和记录类型始终对不齐的原因:“该类目下面是否还有子类目?”把一个嵌套的子类目和“长椅坐垫套装”分开,后者是一个与类目处在同一深度的可售产品,于是“三人花园长椅”比“3 米悬臂遮阳伞”低了一级,尽管两者都是产品。
- “该产品是否有变体?”按文件回答它的方式来回答:有,产出“坐垫套装(本色)”这样带可下单编码的变体行;没有,则产出“长椅坐垫套装(单一 SKU)”,此时产品行本身就是可售行,下面什么也不挂。
- 物料清单那一支,只能经由“是常备库存还是按单生产?”进入:常备库存的条目止于“三人花园长椅(橡木)”,而按单生产的继续走进“是外购还是自制?”,一直向下到“硬木板条组件”和“铸铁长椅框架”。
- 七个叶子行,每一个都是连线到单元格为空的行,它们靠形状而不是靠深度区分——像“3 米替换伞布”这样可售的叶子,对上像“遮阳伞伞骨组件”这样内部使用的叶子,而这正是“该备件是否单独销售?”所决定的事。
何时使用本模板
- 有人发来一份目录导出文件——从 PIM、ERP 或电商后台导出的 CSV——然后问你这条产品线里究竟有些什么。
- 一份物料清单有好几百行,而不靠手工筛选文件,没人看得出某一个组件会用到哪些成品上。
- 两个系统对目录结构各执一词,而你想把两份导出文件画成两棵树,而不是在 diff 里一行一行地比。
- 导出文件里有孤儿行,它们的父级 id 在文件里根本不存在,而你需要在把这份层级加载进别的系统之前先把它们找出来。
- 你要把这条产品线交给供应商、审计人员或新同事,而一列 id 挨着一列父级 id,不是任何人读得下去的东西。
生成此图的 CSV 文件
每行一个步骤。「连线至」列中的数字是行号——正是它画出了连线,也正是大多数文件缺少的那一列。
| # | 形状 | 方框文字 | 连线到 | 连线文字 | 横向泳道 | 纵向泳道 |
|---|---|---|---|---|---|---|
| 1 | Start | 户外生活用品目录 | 2, 3 | 根节点(父级为空) | 类目记录 | |
| 2 | Process | 座椅 | 4 | 深度 1 | 类目记录 | |
| 3 | Process | 遮阳与遮蔽 | 7 | 深度 1 | 类目记录 | |
| 4 | Decision | 该类目下面是否还有子类目? | 5, 6 | 子类目, 可售产品 | 深度 1 | 类目记录 |
| 5 | Process | 长椅 | 10 | 深度 2 | 类目记录 | |
| 6 | Process | 长椅坐垫套装 | 8 | 深度 2 | 产品记录 | |
| 7 | Process | 3 米悬臂遮阳伞 | 9 | 深度 2 | 产品记录 | |
| 8 | Decision | 该产品是否有变体? | 11, 12 | 有,每个变体一行, 没有,产品行本身就是 SKU | 深度 2 | 产品记录 |
| 9 | Decision | 该备件是否单独销售? | 13, 14 | 单独销售, 仅用于维修 | 深度 2 | 产品记录 |
| 10 | Process | 三人花园长椅 | 15 | 深度 3 | 产品记录 | |
| 11 | Success | 坐垫套装(本色) | 深度 3 | 变体记录 | ||
| 12 | Success | 长椅坐垫套装(单一 SKU) | 深度 3 | 产品记录 | ||
| 13 | Success | 3 米替换伞布 | 深度 3 | 变体记录 | ||
| 14 | End | 遮阳伞伞骨组件 | 深度 3 | 组件记录 | ||
| 15 | Decision | 是常备库存还是按单生产? | 17, 16 | 常备库存, 按单生产 | 深度 3 | 产品记录 |
| 16 | Decision | 是外购还是自制? | 18, 19 | 外购, 自制 | 深度 3 | 组件记录 |
| 17 | Success | 三人花园长椅(橡木) | 深度 4 | 变体记录 | ||
| 18 | End | 硬木板条组件 | 深度 4 | 组件记录 | ||
| 19 | End | 铸铁长椅框架 | 深度 4 | 组件记录 |
#,形状,方框文字,连线到,连线文字,横向泳道,纵向泳道
1,Start,户外生活用品目录,"2, 3",,根节点(父级为空),类目记录
2,Process,座椅,4,,深度 1,类目记录
3,Process,遮阳与遮蔽,7,,深度 1,类目记录
4,Decision,该类目下面是否还有子类目?,"5, 6","子类目, 可售产品",深度 1,类目记录
5,Process,长椅,10,,深度 2,类目记录
6,Process,长椅坐垫套装,8,,深度 2,产品记录
7,Process,3 米悬臂遮阳伞,9,,深度 2,产品记录
8,Decision,该产品是否有变体?,"11, 12","有,每个变体一行, 没有,产品行本身就是 SKU",深度 2,产品记录
9,Decision,该备件是否单独销售?,"13, 14","单独销售, 仅用于维修",深度 2,产品记录
10,Process,三人花园长椅,15,,深度 3,产品记录
11,Success,坐垫套装(本色),,,深度 3,变体记录
12,Success,长椅坐垫套装(单一 SKU),,,深度 3,产品记录
13,Success,3 米替换伞布,,,深度 3,变体记录
14,End,遮阳伞伞骨组件,,,深度 3,组件记录
15,Decision,是常备库存还是按单生产?,"17, 16","常备库存, 按单生产",深度 3,产品记录
16,Decision,是外购还是自制?,"18, 19","外购, 自制",深度 3,组件记录
17,Success,三人花园长椅(橡木),,,深度 4,变体记录
18,End,硬木板条组件,,,深度 4,组件记录
19,End,铸铁长椅框架,,,深度 4,组件记录运作方式
找出承载层级的那两列
就这件事而言,导出文件里其余的一切都是陪衬。你需要的是装着每一行自身标识符的那一列,和写出它父级的那一列。它们很少叫 id 和 parent_id:去找 parent_sku、belongs_to、category_path 或 assembly。如果父级是一条路径而不是一个编码,比如“首页 > 座椅 > 长椅”,那么最后一段是父级,前面的部分是深度。如果导出文件根本没有父级列、却有一列层级编号,请看下面关于缩进式物料清单的那条说明。
把父级列反转成连线到
整件事就这一步。把导出文件按父级列排序或分组,让每个父级的子级挨在一起,再把这些子级的行号写进父级的连线到单元格里,用逗号分隔。方向在这里掉头了:导出文件说的是子级写出父级,表格说的是父级写出子级。有一个后果值得说出来——父级列是一行一个值,而连线到有多少个值取决于这一行有多少子级,所以信息从很多行搬到了更少的行上。
最后再给行编号,而且只在顺序定稿之后
连线到装的是这一行在表格里的位置,不是它的标识符,所以 SKU-1042 必须变成带着它的那一行的编号。之后插入一行,插入点以下的每一个数字就都差了一位。请先把行排成最终的顺序,再一遍把 id 解析成编号。指向不存在的行的连线到值,会在画图时被静默丢弃,看上去就像一个方框忘了连向任何地方。
给连线到单元格加引号,并确认分隔符
连线到和连线文字装的是逗号分隔的列表,所以在逗号分隔的文件里,这些单元格必须用双引号包住——“4,5”和“是,否”——否则这一行会多出一个字段,它后面的每一列都向左错开一位。欧洲的导出文件常常是分号分隔的,这让单元格里的逗号变得无害,但整份文件都必须按分号分隔来读。产品名称自带引号方面的麻烦:“长椅, 三人”里的逗号,或者 3" 立柱里的英寸符号,都要照同样的方式转义。如果某一列导入后像是被忽略了,请检查第一个表头名称,因为一份带字节顺序标记的 UTF-8 文件会在它前面藏着三个看不见的字节。
形状由这一行是什么决定,横向泳道和纵向泳道由它在哪里决定
有一行取开始:父级为空的那一行。连线到为空的行是叶子,而叶子需要一个终止形状——结束、成功或拒绝——因为一个非终止的行没有出去的连线就是一条死路。如果有帮助,就照这份模板的分法来:客户能下单的行用成功,只存在于组件内部的行用结束。然后把你走出来的深度填进横向泳道,把导出文件自带的类型列填进纵向泳道。认不出来的形状名称会被无声地规整成流程,所以尤其要检查决策这个词有没有写错。
导入前先清掉孤儿、多余的根和环
三项检查,各有各的症状。父级列里的每一个值都必须出现在 id 列里;没有出现的就是孤儿,通常是因为导出时只筛了一个类目,而它们的父级在这个类目之上。父级为空的行应当恰好有一个,如果有好几个,你面对的就是好几棵树。而且任何一行都不能顺着父级回到它自己,这种情况出现在一次糟糕的合并之后,反转过来会画出一条绕回自身的连线。
常见问题
怎样把一列父级和子级变成流程图?
先反转这个关系,再给它编号。导出文件给你的是子级写出父级;表格要的是父级写出子级。把行按父级列分组,对每一个父级,把它的子级的行号写进这个父级的连线到单元格里,用逗号分隔。父级单元格为空的每一行都是根节点,取开始形状;没有出现在任何一行父级列里的行都是叶子,连线到留空并取一个终止形状。方框文字取自名称列,横向泳道取自你顺着父级链走出来的深度,纵向泳道取自导出文件已有的类型列。然后把 .csv 拖到编辑器的表格区域上,或者直接把 CSV 文本粘贴进去。导入按表头名称匹配,所以你文件里的列顺序无关紧要,它认不出来的列会被带过并忽略。
父级列和连线到列有什么区别?
方向、基数,以及值指的是什么。父级列朝上指:每一行写出它上面那唯一的一行,所以一行恰好一个值,而叶子就是没人写出的那些行。连线到列朝下指:每一行写出它下面的那些行,所以一个有四个子级的父级在一个单元格里装四个值,而叶子就是单元格为空的那些行。而且两者的值在种类上也不同。父级列装的是标识符,像 SKU-1042 这样的东西,它跟着这一行走到哪里都不变。连线到装的是位置,也就是这一行在表格里从 1 数起的编号,只要上面插入一行它就变了。这正是标识符必须在行序定稿之后、而不是之前解析成编号的原因。
我的列从文件中间开始整体错位了,发生了什么?
几乎总是一个没有加引号的逗号。CSV 的一行在任何东西看它之前就先按分隔符切开了,所以在逗号分隔的文件里,一个装着“4,5”的连线到单元格会被读成两个字段,这一行就比表头多出一个字段,而连线到后面的每一列都落到了邻居的标题下面。把这些单元格用双引号包起来,解析器就会把它们拼回去。同样也适用于连线文字,它也是一个逗号分隔的列表,以及任何名称里带逗号的产品。如果错位是从第一列就开始的,那么原因通常相反:这份文件是分号分隔的——多数欧洲系统导出的正是这种——却被当成逗号分隔来读;或者编码不匹配,让一个字节顺序标记粘在了第一个表头名称上,于是它再也匹配不上了。
父级不在导出文件里的那一行会怎样?
它变成孤儿,而这是筛选过的导出文件里最常见的缺陷。你向系统要了一个类目,或者只要在售的条目,它就恰好给了你这些行——连同它们的父级 id,而这些 id 指向的行被筛掉了。文件里没有任何东西标明这有问题。层级反转之后,这一行根本不会出现在任何人的连线到里,于是它画出来是一个没有任何箭头进来的方框,孤立在树之外。请在导入之前逐行判断它属于哪一种:父级被筛掉的行,应当重新挂到最近的、包含在文件里的祖先上;而父级在源系统里已经不存在的行,是一个该退回去修的数据缺陷,不是一个该画出来的东西。
我的物料清单只有层级列而没有父级列,可以用吗?
可以,转换出来是同一个东西,只不过这次转换依赖的是行的顺序而不是行里的任何值。缩进式物料清单沿着文件重复 1、2、2、3、1 这样的层级,规则是某一行的父级是它上面最近的、层级恰好小一级的那一行。这意味着导出文件原本的顺序是承重的——先按物料号给文件排个序,层级就没了,既不报错,也没有任何东西能把它找回来。请从上到下走一遍文件,记住每一级最后见到的那一行,边走边指定父级,然后才反转成连线到。数量、单位和供应商编码可以留在它们自己的列里,导入时会被带过并忽略;如果你希望它们可见,就搬进备注列。