在PostgreSQL中拆分人名的最简单方法是什么?

4
考虑一个包含完整人名的表格:
create table names (full_name varchar not null);   
insert into names (full_name) 
  values ('Jane Marie Doe'), ('John Doe');

在Postgres中,将名称拆分为名字和姓氏的最简单(最易读)的方法是什么?
 first_name | last_name 
------------+-----------
 Jane Marie | Doe
 John       | Doe
(2 rows)

这是我想出来的方法,但似乎非常复杂。肯定有更简单的方法吧?
select 
  array_to_string(ary[1:len - 1], ' ') as first_name, 
  ary[len] as last_name 
from (
  select ary, array_length(ary, 1) as len
  from (
    select regexp_split_to_array(full_name, E'\\s+') as ary 
    from names
  ) sub1
) sub2;

2
你的表格设计有误。你应该拥有名字(first_name)和姓氏(last_name)两列。 - Rahul
8
回复:“你的表格设计有问题”。我同意,我正在将一个已有的表格迁移到两列设计,谢谢。 - anon
5
实际上,我认为你原来的表格设计更好,因为并非所有人都有名字和姓氏。无论如何,如果你的表格中有Robert J. Van de Graaff或Pancakes McGee Jr.这样的人物,你将会怎么做? - mu is too short
3
那么你的老板将会得到他们应得的错误数据 =D - StingyJack
3
作为参考,出版行业长期存在一个问题,在国际环境下尤其如此,即公开传达姓名。出版业的“ONIX” XML标准现在指定了八个组件:<TitlesBeforeNames>、<NamesBeforeKey>、<PrefixToKey>、<KeyNames>、<NamesAfterKey>、<SuffixToKey>、<LettersAfterNames>、<TitlesAfterNames>。它允许精确指定如“van”、“Jr”、“His Holiness”、“MBA FRCS”、“Ibrahim”等名字组件。如果您聪明的话,您还可以添加“发音指南”和其他偏好设置。 - David Aldridge
显示剩余4条评论
5个回答

7

您可以尝试

SELECT regexp_split_to_array(full_name, E'\\s\\S+') as ary

相反,应该始终在最后一个空格处拆分,这样你就知道 ary 只有两个成员。

编辑: 经过进一步思考,我认为最好的方法可能是使用

SELECT regexp_replace(full_name,'\s\S+','') as first_name
SELECT regexp_replace(full_name,'.+[\s]','') as last_name

好主意,但您的模式(E'\\s\\S+$')包括定界符中的姓氏,因此返回的数组的第二个元素将是空字符串。这适用于查找名字,不过。 - anon
2
处理具有多个空格的项目很奇怪。例如,DR SOMIDDHO DEBNATH MD 会产生 DR DEBNATH MD + MD - expert
SELECT regexp_replace(full_name,'(.+)\s\S+$','\1') as first_name SELECT regexp_replace(full_name,'.+[\s]','') as last_name - moonshot

4
为了记录,当前设计是正确的,您不应该更改它
如果您尝试这样做,唯一比较正确的方法是询问每个用户的名字部分。如果您愿意,可以尝试猜测简单的两部分名称,但即使如此,您也不知道“金希澜”是“金,希澜”还是“希澜,金”。
我曾与一家公司合作进行过姓名拆分。他们以迄今为止我见过的最不可怕的方式完成了它:
  • 提前向所有用户发送电子邮件告知他们
  • 将“姓名”字段更改为“首选显示名称”
  • 添加新的“名”和“姓”字段,避免混淆他们被称为“名字”和“姓氏”
  • 为具有英文化和母语名称、音译和原字符集名称等人添加新字段“备用名称”
  • 尝试猜测简单的名称,保留其余名称不变
  • 向用户发送电子邮件,为他们提供一个页面,他们可以在其中检查名称拆分(如果已猜测)或输入其名称部分(如果未猜测)。
  • 明确指出,如果您只有一个名字,可以在名字字段中输入它并留空姓氏。没有强制性的姓氏要求。
  • 没有试图验证名称。您的名字是~~M^2?很好,你很奇怪。
  • 不强制大小写、空格等。像“德文”这样的名字是可以的
  • 不会搞砸他们的文本编码处理。
基本上,任何尝试使用正则表达式拆分名称的方法都是错误的。如果您真的坚持这样做,请仅针对“看起来”简单的名称,例如:
SELECT regexp_matches('Fred Smith', '^([A-Z][[:alpha:]]+) ([A-Z][[:alpha:]]+)$');

这将仅匹配具有两个明显部分的姓名,两个部分都以大写字母开头,并且仅包含字母(带重音符号或不带)。即使这样,它也无法解决“名字和姓氏顺序颠倒”的问题。其他名称将不匹配,应保留原样供用户更改。


这真的很有启发性,但严格来说并不是问题的答案。不过还是谢谢。 - anon

1

使用字符串函数还有另一种方法。从末尾找到第一个空格并将其选择为last name,然后在原始字符串中replace last name字符串为''

with lname as 
(select name, 
reverse(substr(reverse(name),1,strpos(reverse(name),' '))) as last_name
from names)
select replace(name,last_name,'') as first_name, last_name
from lname

0

将名字的姓和名分开的简单方法:

select regexp_replace('John Martin Doe','\\s.*','') as first_name, regexp_replace('John Martin Doe','[a-zA-Z]+','') as last_name;

0

最佳答案提供了正确的姓氏正则表达式。对于名字,它并不适用于 OP 提供的样本,例如 "Jane Marie Doe"。您需要一个带有捕获组的正则表达式:

SELECT regexp_replace(full_name,'(.+)\s\S+$','\1') as first_name 
SELECT regexp_replace(full_name,'.+[\s]','') as last_name

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接