《老何的1001夜》,Qunar小伙伴们都懂的
1.问题的提出
我们wrapper里头有个表叫 rtr,用于保存抽取出来的线路,其中有个字段,是 cities,用于保存对应线路抽取出来的途径的城市,为了便于开发和数据交流,这个字段保存的是符号分隔的城市字串,准确说,就是用 0x03 分隔的,中文城市列表,现在有个这样的需求:我们希望统计一下这个途径城市相同的线路有多少。
2.问题的分析
这个问题看似简单,其实还是挺费劲的,我们可以利用的机制有:
PostgreSQL 里有个函数 string_to_array() 是可以把符号分隔的字串变成数组来使用的
PostgreSQL 的数组是可以用等于号(=)进行比较的
PostgreSQL 要求相同的数组必须顺序相同
我们面临的困难:
抽取的过程输出的城市列表是无序的,比如,会有“北京,上海,广州",和”上海,北京,广州"的区别
0x03 是不可见字符
3.问题的解决
思考了下,解决思路是这样的:
把 0x03 替换成标准分隔符,比如逗号(,)
把逗号分隔的字串通过某种方法生成排序的数组,保证顺序相同
比较最后生成的有序数组
这个解法比较难的是第二步,这里我们要利用下面几个条件:
PostgreSQL 有个 unnest() 函数可以把数组展开成数据行
数据行是可以排序的
这个表里头有主键,因此我们可以按照主键排序并最后重组对应的城市列表数组
写出来的查询是下面这个样子:
select rid, array_agg(city) as cities from (select rid, unnest(string_to_array(replace(cities, E'\x03', ','), ',')) city from rtr order by rid, city limit 10) a group by rid;
复制
这样输出来的 cities,就是有序的数组,可以进行任意比较了,比如,group by cities,就可以看看有多少分组,并且 order by之后,还可以看看分组之间的差异有多大。
4.改进
思考了一下,感觉那个 replace() 的调用是多余的,所以可以直接这样:
select rid, array_agg(city) as cities from (select rid, unnest(string_to_array(cities, E'\x03')) city from rtr order by rid, city limit 10) a group by rid;
复制
何伟平
去哪儿网/旅游度假事业部
搜索技术研究人员和数据库研究人员,PostgreSQL 中文手册第一个版本的译者和 Programming Perl 第三版的译者。长期关注在搜索技术、分布式技术、数据库技术和集群设计组织管理行业。曾在雅虎中国负责网页搜索技术部门。在IT圈有着接近18年的从业经验。2010年加入Qunar,先后创建和开发去哪儿攻略搜索频道、去哪儿团购频道,现负责 Qunar.com 度假业务部门。
文章转自公司wiki《老何的1001夜》,Qunar小伙伴可以登录wiki查看更多文章
点击“阅读原文”,查看历史文章。