PSQL技术需求:基于视图中PARENT列唯一值实现CHILD列值的唯一性
解决PARENT与CHILD唯一映射的更新方案
首先咱们明确需求:要让视图里每个唯一的PARENT值对应唯一的CHILD值,如果当前CHILD被多个PARENT共享,就通过在CHILD的-符号前追加字符的方式修改,最终达到一一映射的目的。
问题分析
看你给出的初始数据,存在两个冲突场景:
BBB - 364同时对应ABC - 123和GHI - 789两个PARENTNNN - 679同时对应JKL - 343和MNO - 524两个PARENT
咱们的目标就是给这些冲突的PARENT对应的CHILD添加唯一标识,让每个PARENT有专属的CHILD。
解决方案思路
- 识别冲突组:用窗口函数找出每个CHILD对应的PARENT数量,标记出被多个PARENT共享的CHILD
- 生成唯一后缀:对每个冲突CHILD下的PARENT分组,给每个PARENT分配唯一的序号,用序号对应字母追加到CHILD前缀后
- 更新CHILD列:根据标记的冲突记录,修改对应的CHILD值
具体SQL实现(以MySQL为例)
第一步:先查看冲突记录(可选,用于验证)
SELECT ID, PARENT, CHILD, -- 统计当前CHILD对应的不同PARENT数量 COUNT(DISTINCT PARENT) OVER (PARTITION BY CHILD) AS parent_count, -- 给当前CHILD下的PARENT排序,序号用于生成唯一标识 ROW_NUMBER() OVER (PARTITION BY CHILD ORDER BY ID) AS rn FROM your_view;
这个查询会帮你清晰看到哪些CHILD存在冲突,以及每个PARENT在冲突组里的排序。
第二步:执行更新操作
UPDATE your_view JOIN ( SELECT PARENT, COUNT(DISTINCT PARENT) OVER (PARTITION BY CHILD) AS parent_count, ROW_NUMBER() OVER (PARTITION BY CHILD ORDER BY ID) AS rn FROM your_view ) AS sub ON your_view.PARENT = sub.PARENT SET CHILD = CONCAT( -- 拆分CHILD的前缀部分(-之前的内容) SUBSTRING_INDEX(your_view.CHILD, '-', 1), -- 给排序序号>1的记录追加字母(rn=2对应A,rn=3对应B,以此类推) CASE WHEN sub.rn > 1 THEN CHAR(64 + sub.rn) ELSE '' END, '-', -- 拆分CHILD的后缀部分(-之后的内容) SUBSTRING_INDEX(your_view.CHILD, '-', -1) ) -- 只更新存在冲突且不是组内第一条的记录 WHERE sub.parent_count > 1 AND sub.rn > 1;
代码说明
PARTITION BY CHILD:按CHILD分组,统计每个CHILD对应的PARENT数量ROW_NUMBER() OVER (...):给每个CHILD组内的PARENT排序,这里按ID排序,你可以改成按PARENT或者其他字段,决定哪个PARENT保留原CHILD值CHAR(64 + sub.rn):利用ASCII码生成字母,65是A,所以rn=2对应A,rn=3对应B,刚好满足追加唯一字符的需求SUBSTRING_INDEX:拆分CHILD的前缀和后缀,保证修改后只改变-前的部分
匹配示例效果
执行完上面的SQL后,你的数据会和预期结果一致:
ABC - 123对应的CHILD变成BBBA - 364(因为它是BBB - 364组内的第二条记录,rn=2,追加A)- 如果要改成示例里
JKL - 343对应的NNNQ - 679,只需要把CHAR(64 + sub.rn)改成自定义的字符映射即可,比如用CASE语句指定特定字符:CASE WHEN sub.rn = 2 THEN 'Q' WHEN sub.rn = 3 THEN 'R' ELSE '' END
如果是其他数据库(比如SQL Server、Oracle),只需要调整字符串拆分函数即可:
- SQL Server用
LEFT(CHILD, CHARINDEX('-', CHILD)-1)和RIGHT(CHILD, LEN(CHILD)-CHARINDEX('-', CHILD)) - Oracle用
SUBSTR(CHILD, 1, INSTR(CHILD, '-')-1)和SUBSTR(CHILD, INSTR(CHILD, '-')+1)
内容的提问来源于stack exchange,提问作者JJ13596




