PostgreSQL中如何将name列拆分迁移为first_name和last_name列
问题根因
regexp_match(name, '[^\s]*')返回带{}的结果,是因为PostgreSQL中regexp_match的返回值是text[]文本数组类型,直接把数组赋值给文本类型字段,就会输出PostgreSQL数组默认的花括号包裹格式,不是你需要的纯字符串。
推荐实现:基础字符串函数方案(性能最高)
完全不需要用正则,用内置字符串定位、截取函数性能远高于正则,也100%匹配「第一个空白字符为分界」的规则,同时兼容name中无空白字符的边界场景(无空白时first_name取完整值,last_name为空):
UPDATE users SET (first_name, last_name) = ( TRIM(LEADING FROM SUBSTRING(name FOR STRPOS(name, ' '))), TRIM(LEADING FROM SUBSTRING(name FROM STRPOS(name, ' ') + 1)) );
注意:不要用
split_part实现该逻辑,该函数仅能返回分隔后的指定序号分段,会丢失第一个空格后的多段内容,比如John Doe Jr会被拆成first_name=John、last_name=Doe,丢失Jr部分,不符合需求。
语句中加TRIM(LEADING ...)是为了兼容第一个空格前有连续多空白、name开头带空白的脏数据,如果你的数据格式完全规范,可以去掉trim逻辑。
测试name='John Doe Jr'场景时,执行后first_name='John',last_name='Doe Jr',完全符合拆分规则。
正则写法修复
如果一定要用正则实现,只需要取regexp_match返回数组的第一个元素即可,不要直接把数组赋值给字段:
UPDATE users SET (first_name, last_name) = ( (regexp_match(name, '^[^\s]+'))[1], TRIM(LEADING FROM regexp_replace(name, '^[^\s]+\s+', '')) );
该写法效果和字符串函数方案一致,但正则匹配有额外性能开销,大批量数据迁移场景不推荐使用。
内容的提问来源于stack exchange,提问作者ussu
相关产品推荐
相关产品推荐

