我如何解析第一,中间和最后一个名字用SQL全称场的?
我需要尝试匹配上不上全名直接匹配的名字。 我希望能够采取全名字段,把它分解成第一,中间名和姓。
该数据不包括任何前缀或后缀。 中间名是可选的。 该数据被格式化“中间名姓”。
我感兴趣的是一些实际的解决方案,让我90%的方式出现。 正如已经指出,这是一个复杂的问题,所以我会单独处理特殊情况。
我如何解析第一,中间和最后一个名字用SQL全称场的?
我需要尝试匹配上不上全名直接匹配的名字。 我希望能够采取全名字段,把它分解成第一,中间名和姓。
该数据不包括任何前缀或后缀。 中间名是可选的。 该数据被格式化“中间名姓”。
我感兴趣的是一些实际的解决方案,让我90%的方式出现。 正如已经指出,这是一个复杂的问题,所以我会单独处理特殊情况。
这里是一个自包含的例子中,与易于操作的测试数据。
有了这个例子,如果你有超过三个部分的名称,那么所有的“额外”的东西将得到放在LAST_NAME领域。 一个例外是针对被确定为“标题”特定字符串,如“DR”,“MRS”和“MR”制造。
如果中间名丢失,那么你只会得到FIRST_NAME和last_name(MIDDLE_NAME将是NULL)。
你可以粉碎成子的一个巨大的嵌套斑点,但可读性比较辛苦,因为它是当你这样做的SQL。
Edit--处理以下特殊情况:
1 - NAME字段是NULL
2 - name字段包含前/后间隔
3 - NAME字段的名称为内> 1个连续空间
4 - name字段包含只有第一个名字
5 -包括作为一个单独的列最终输出的原始全名,可读性
6 -处理前缀的特定列表作为单独的“标题”一栏
SELECT
FIRST_NAME.ORIGINAL_INPUT_DATA
,FIRST_NAME.TITLE
,FIRST_NAME.FIRST_NAME
,CASE WHEN 0 = CHARINDEX(' ',FIRST_NAME.REST_OF_NAME)
THEN NULL --no more spaces? assume rest is the last name
ELSE SUBSTRING(
FIRST_NAME.REST_OF_NAME
,1
,CHARINDEX(' ',FIRST_NAME.REST_OF_NAME)-1
)
END AS MIDDLE_NAME
,SUBSTRING(
FIRST_NAME.REST_OF_NAME
,1 + CHARINDEX(' ',FIRST_NAME.REST_OF_NAME)
,LEN(FIRST_NAME.REST_OF_NAME)
) AS LAST_NAME
FROM
(
SELECT
TITLE.TITLE
,CASE WHEN 0 = CHARINDEX(' ',TITLE.REST_OF_NAME)
THEN TITLE.REST_OF_NAME --No space? return the whole thing
ELSE SUBSTRING(
TITLE.REST_OF_NAME
,1
,CHARINDEX(' ',TITLE.REST_OF_NAME)-1
)
END AS FIRST_NAME
,CASE WHEN 0 = CHARINDEX(' ',TITLE.REST_OF_NAME)
THEN NULL --no spaces @ all? then 1st name is all we have
ELSE SUBSTRING(
TITLE.REST_OF_NAME
,CHARINDEX(' ',TITLE.REST_OF_NAME)+1
,LEN(TITLE.REST_OF_NAME)
)
END AS REST_OF_NAME
,TITLE.ORIGINAL_INPUT_DATA
FROM
(
SELECT
--if the first three characters are in this list,
--then pull it as a "title". otherwise return NULL for title.
CASE WHEN SUBSTRING(TEST_DATA.FULL_NAME,1,3) IN ('MR ','MS ','DR ','MRS')
THEN LTRIM(RTRIM(SUBSTRING(TEST_DATA.FULL_NAME,1,3)))
ELSE NULL
END AS TITLE
--if you change the list, don't forget to change it here, too.
--so much for the DRY prinicple...
,CASE WHEN SUBSTRING(TEST_DATA.FULL_NAME,1,3) IN ('MR ','MS ','DR ','MRS')
THEN LTRIM(RTRIM(SUBSTRING(TEST_DATA.FULL_NAME,4,LEN(TEST_DATA.FULL_NAME))))
ELSE LTRIM(RTRIM(TEST_DATA.FULL_NAME))
END AS REST_OF_NAME
,TEST_DATA.ORIGINAL_INPUT_DATA
FROM
(
SELECT
--trim leading & trailing spaces before trying to process
--disallow extra spaces *within* the name
REPLACE(REPLACE(LTRIM(RTRIM(FULL_NAME)),' ',' '),' ',' ') AS FULL_NAME
,FULL_NAME AS ORIGINAL_INPUT_DATA
FROM
(
--if you use this, then replace the following
--block with your actual table
SELECT 'GEORGE W BUSH' AS FULL_NAME
UNION SELECT 'SUSAN B ANTHONY' AS FULL_NAME
UNION SELECT 'ALEXANDER HAMILTON' AS FULL_NAME
UNION SELECT 'OSAMA BIN LADEN JR' AS FULL_NAME
UNION SELECT 'MARTIN J VAN BUREN SENIOR III' AS FULL_NAME
UNION SELECT 'TOMMY' AS FULL_NAME
UNION SELECT 'BILLY' AS FULL_NAME
UNION SELECT NULL AS FULL_NAME
UNION SELECT ' ' AS FULL_NAME
UNION SELECT ' JOHN JACOB SMITH' AS FULL_NAME
UNION SELECT ' DR SANJAY GUPTA' AS FULL_NAME
UNION SELECT 'DR JOHN S HOPKINS' AS FULL_NAME
UNION SELECT ' MRS SUSAN ADAMS' AS FULL_NAME
UNION SELECT ' MS AUGUSTA ADA KING ' AS FULL_NAME
) RAW_DATA
) TEST_DATA
) TITLE
) FIRST_NAME
这很难不知道“全名”是如何格式化回答。
这可能是“姓,名中间名”或“名字中间名姓”,等等。
基本上你将不得不使用字符串函数
SUBSTRING ( expression , start , length )
大概CHARINDEX函数
CHARINDEX (substr, expression)
为了弄清楚你要提取每个部分的开始和长度。
所以我们说的格式为“姓氏名字”你可以(未经测试..但应该接近):
SELECT
SUBSTRING(fullname, 1, CHARINDEX(' ', fullname) - 1) AS FirstName,
SUBSTRING(fullname, CHARINDEX(' ', fullname) + 1, len(fullname)) AS LastName
FROM YourTable
反向的问题,添加列举行单独的块并且将它们结合起来,以获得全名。
这将是最好的答案的原因是,有找出已注册为他们的名字一个人没有保证的方式,什么是他们的中间名。
举例来说,你会如何分割呢?
Jan Olav Olsen Heggelien
这一点,而被虚构的,是挪威法律的名称,可以,但不会有,分裂是这样的:
First name: Jan Olav
Middle name: Olsen
Last name: Heggelien
或者,像这样:
First name: Jan Olav
Last name: Olsen Heggelien
或者,像这样:
First name: Jan
Middle name: Olav
Last name: Olsen Heggelien
我可以想象类似occurances可以在大多数语言中找到。
因此,而不是试图解释不具有足够的信息来得到它的权利,存储正确的解释,并结合以获得全名数据。
除非你有非常,非常乖巧的数据,这是一个不平凡的挑战。 一个天真的做法是来标记上的空白,并假定三令牌的结果是[第一,中间,最后]和双令牌的结果是[第一,最后],但你将不得不面对多字的姓(例如,“范布伦”)和多个中间名。
替代简单的方法是使用parsename
:
select full_name,
parsename(replace(full_name, ' ', '.'), 3) as FirstName,
parsename(replace(full_name, ' ', '.'), 2) as MiddleName,
parsename(replace(full_name, ' ', '.'), 1) as LastName
from YourTableName
资源
对于一个免费的SQL CLR基础的解决方案一定要与环境的概念,可以是一个很大的帮助,在数据库级别解析名称退房SqlName。
http://ambientconcepts.com/sqlname
你确定完整的法定名称将始终包括第一,中间和最后一个? 我知道,只有一个名字的法定全名的人,和诚实,我不知道这是他们的名字或姓氏。 :-)我也知道,在他们的法定名称有不止一个最前一页名字的人,但没有一个中间名。 还有一些人认为有多个中间名。
再有就是还法人全称名称的顺序。 据我所知,在一些亚洲文化的姓氏是第一位在法定的全称。
在一个更实际的音符,你可以在空白和威胁分裂全称中头一个令牌名和最后一个令牌(或只有一个名字的情况下,只是象征性地)为姓。 虽然这个假设订货会总是相同的。
像1号说,这不是小事。 复姓姓氏,首字母,双名,逆名序列和各种其他异常的能毁掉你精心打造的功能。
你可以使用一个第三方库(插头/免责声明 - 我从事这个产品):
http://www.melissadata.com/nameobject/nameobject.htm
我会做这是一个反复的过程。
1)转储表到平面文件一起工作。
2)写一个简单的程序,打破了你的名称中使用空格作为分隔符,其中首创令牌是第一个名字,如果有3个令牌,然后令牌2中间名和令牌3是姓。 如果有2个记号然后第二个标记的姓氏。 (Perl中,Java或C / C ++语言并不重要)
3)眼球的结果。 寻找那些不符合这一规则的名称。
4)用这个例子中,创建一个新的规则来处理这个异常...
5)冲洗和重复
最终你会得到解决您所有的数据的程序。
如果你试图解析除了人的名字在PHP中,我建议基思·贝克曼的nameparse.php脚本 。
在现场的情况下复制下山:
<?
/*
Name: nameparse.php
Version: 0.2a
Date: 030507
First: 030407
License: GNU General Public License v2
Bugs: If one of the words in the middle name is Ben (or St., for that matter),
or any other possible last-name prefix, the name MUST be entered in
last-name-first format. If the last-name parsing routines get ahold
of any prefix, they tie up the rest of the name up to the suffix. i.e.:
William Ben Carey would yield 'Ben Carey' as the last name, while,
Carey, William Ben would yield 'Carey' as last and 'Ben' as middle.
This is a problem inherent in the prefix-parsing routines algorithm,
and probably will not be fixed. It's not my fault that there's some
odd overlap between various languages. Just don't name your kids
'Something Ben Something', and you should be alright.
*/
function norm_str($string) {
return trim(strtolower(
str_replace('.','',$string)));
}
function in_array_norm($needle,$haystack) {
return in_array(norm_str($needle),$haystack);
}
function parse_name($fullname) {
$titles = array('dr','miss','mr','mrs','ms','judge');
$prefices = array('ben','bin','da','dal','de','del','der','de','e',
'la','le','san','st','ste','van','vel','von');
$suffices = array('esq','esquire','jr','sr','2','ii','iii','iv');
$pieces = explode(',',preg_replace('/\s+/',' ',trim($fullname)));
$n_pieces = count($pieces);
switch($n_pieces) {
case 1: // array(title first middles last suffix)
$subp = explode(' ',trim($pieces[0]));
$n_subp = count($subp);
for($i = 0; $i < $n_subp; $i++) {
$curr = trim($subp[$i]);
$next = trim($subp[$i+1]);
if($i == 0 && in_array_norm($curr,$titles)) {
$out['title'] = $curr;
continue;
}
if(!$out['first']) {
$out['first'] = $curr;
continue;
}
if($i == $n_subp-2 && $next && in_array_norm($next,$suffices)) {
if($out['last']) {
$out['last'] .= " $curr";
}
else {
$out['last'] = $curr;
}
$out['suffix'] = $next;
break;
}
if($i == $n_subp-1) {
if($out['last']) {
$out['last'] .= " $curr";
}
else {
$out['last'] = $curr;
}
continue;
}
if(in_array_norm($curr,$prefices)) {
if($out['last']) {
$out['last'] .= " $curr";
}
else {
$out['last'] = $curr;
}
continue;
}
if($next == 'y' || $next == 'Y') {
if($out['last']) {
$out['last'] .= " $curr";
}
else {
$out['last'] = $curr;
}
continue;
}
if($out['last']) {
$out['last'] .= " $curr";
continue;
}
if($out['middle']) {
$out['middle'] .= " $curr";
}
else {
$out['middle'] = $curr;
}
}
break;
case 2:
switch(in_array_norm($pieces[1],$suffices)) {
case TRUE: // array(title first middles last,suffix)
$subp = explode(' ',trim($pieces[0]));
$n_subp = count($subp);
for($i = 0; $i < $n_subp; $i++) {
$curr = trim($subp[$i]);
$next = trim($subp[$i+1]);
if($i == 0 && in_array_norm($curr,$titles)) {
$out['title'] = $curr;
continue;
}
if(!$out['first']) {
$out['first'] = $curr;
continue;
}
if($i == $n_subp-1) {
if($out['last']) {
$out['last'] .= " $curr";
}
else {
$out['last'] = $curr;
}
continue;
}
if(in_array_norm($curr,$prefices)) {
if($out['last']) {
$out['last'] .= " $curr";
}
else {
$out['last'] = $curr;
}
continue;
}
if($next == 'y' || $next == 'Y') {
if($out['last']) {
$out['last'] .= " $curr";
}
else {
$out['last'] = $curr;
}
continue;
}
if($out['last']) {
$out['last'] .= " $curr";
continue;
}
if($out['middle']) {
$out['middle'] .= " $curr";
}
else {
$out['middle'] = $curr;
}
}
$out['suffix'] = trim($pieces[1]);
break;
case FALSE: // array(last,title first middles suffix)
$subp = explode(' ',trim($pieces[1]));
$n_subp = count($subp);
for($i = 0; $i < $n_subp; $i++) {
$curr = trim($subp[$i]);
$next = trim($subp[$i+1]);
if($i == 0 && in_array_norm($curr,$titles)) {
$out['title'] = $curr;
continue;
}
if(!$out['first']) {
$out['first'] = $curr;
continue;
}
if($i == $n_subp-2 && $next &&
in_array_norm($next,$suffices)) {
if($out['middle']) {
$out['middle'] .= " $curr";
}
else {
$out['middle'] = $curr;
}
$out['suffix'] = $next;
break;
}
if($i == $n_subp-1 && in_array_norm($curr,$suffices)) {
$out['suffix'] = $curr;
continue;
}
if($out['middle']) {
$out['middle'] .= " $curr";
}
else {
$out['middle'] = $curr;
}
}
$out['last'] = $pieces[0];
break;
}
unset($pieces);
break;
case 3: // array(last,title first middles,suffix)
$subp = explode(' ',trim($pieces[1]));
$n_subp = count($subp);
for($i = 0; $i < $n_subp; $i++) {
$curr = trim($subp[$i]);
$next = trim($subp[$i+1]);
if($i == 0 && in_array_norm($curr,$titles)) {
$out['title'] = $curr;
continue;
}
if(!$out['first']) {
$out['first'] = $curr;
continue;
}
if($out['middle']) {
$out['middle'] .= " $curr";
}
else {
$out['middle'] = $curr;
}
}
$out['last'] = trim($pieces[0]);
$out['suffix'] = trim($pieces[2]);
break;
default: // unparseable
unset($pieces);
break;
}
return $out;
}
?>
这将案件串的工作是名字/中间名/姓
Select
DISTINCT NAMES ,
SUBSTRING(NAMES , 1, CHARINDEX(' ', NAMES) - 1) as FirstName,
RTRIM(LTRIM(REPLACE(REPLACE(NAMES,SUBSTRING(NAMES , 1, CHARINDEX(' ', NAMES) - 1),''),REVERSE( LEFT( REVERSE(NAMES), CHARINDEX(' ', REVERSE(NAMES))-1 ) ),'')))as MiddleName,
REVERSE( LEFT( REVERSE(NAMES), CHARINDEX(' ', REVERSE(NAMES))-1 ) ) as LastName
From TABLENAME
我建议快报为learnin /建筑/测试正则表达式。 旧的免费版本 , 新的商业版本
我曾经做了一个500字正则表达式来分析第一,最后和中间名从任意的字符串。 即使考虑到这鸣喇叭正则表达式,它仅仅%的准确率大约97了由于输入的完全不一致。 不过,聊胜于无。
除已经被提出了关于名称和其他异常情况的空间的注意事项,下面的代码将至少处理名字的98%。 (注:凌乱的SQL,因为我没有在我使用数据库正则表达式选项。)
**警告:凌乱的SQL如下:
create table parsname (fullname char(50), name1 char(30), name2 char(30), name3 char(30), name4 char(40));
insert into parsname (fullname) select fullname from ImportTable;
update parsname set name1 = substring(fullname, 1, locate(' ', fullname)),
fullname = ltrim(substring(fullname, locate(' ', fullname), length(fullname)))
where locate(' ', rtrim(fullname)) > 0;
update parsname set name2 = substring(fullname, 1, locate(' ', fullname)),
fullname = ltrim(substring(fullname, locate(' ', fullname), length(fullname)))
where locate(' ', rtrim(fullname)) > 0;
update parsname set name3 = substring(fullname, 1, locate(' ', fullname)),
fullname = ltrim(substring(fullname, locate(' ', fullname), length(fullname)))
where locate(' ', rtrim(fullname)) > 0;
update parsname set name4 = substring(fullname, 1, locate(' ', fullname)),
fullname = ltrim(substring(fullname, locate(' ', fullname), length(fullname)))
where locate(' ', rtrim(fullname)) > 0;
// fullname now contains the last word in the string.
select fullname as FirstName, '' as MiddleName, '' as LastName from parsname where fullname is not null and name1 is null and name2 is null
union all
select name1 as FirstName, name2 as MiddleName, fullname as LastName from parsname where name1 is not null and name3 is null
代码工作通过创建临时表(parsname),并用空格令牌化的全名。 任何在名称3或NAME4值结束了名称是不符合要求的,需要与不同的处理。
下面是将会把发现到名字的最后一个字为姓之间的一切到中间名的第一个字的存储过程。
create procedure [dbo].[import_ParseName]
(
@FullName nvarchar(max),
@FirstName nvarchar(255) output,
@MiddleName nvarchar(255) output,
@LastName nvarchar(255) output
)
as
begin
set @FirstName = ''
set @MiddleName = ''
set @LastName = ''
set @FullName = ltrim(rtrim(@FullName))
declare @ReverseFullName nvarchar(max)
set @ReverseFullName = reverse(@FullName)
declare @lengthOfFullName int
declare @endOfFirstName int
declare @beginningOfLastName int
set @lengthOfFullName = len(@FullName)
set @endOfFirstName = charindex(' ', @FullName)
set @beginningOfLastName = @lengthOfFullName - charindex(' ', @ReverseFullName) + 1
set @FirstName = case when @endOfFirstName <> 0
then substring(@FullName, 1, @endOfFirstName - 1)
else ''
end
set @MiddleName = case when (@endOfFirstName <> 0 and @beginningOfLastName <> 0 and @beginningOfLastName > @endOfFirstName)
then ltrim(rtrim(substring(@FullName, @endOfFirstName , @beginningOfLastName - @endOfFirstName)))
else ''
end
set @LastName = case when @beginningOfLastName <> 0
then substring(@FullName, @beginningOfLastName + 1 , @lengthOfFullName - @beginningOfLastName)
else ''
end
return
end
下面是我在呼唤它。
DECLARE @FirstName nvarchar(255),
@MiddleName nvarchar(255),
@LastName nvarchar(255)
EXEC [dbo].[import_ParseName]
@FullName = N'Scott The Other Scott Kowalczyk',
@FirstName = @FirstName OUTPUT,
@MiddleName = @MiddleName OUTPUT,
@LastName = @LastName OUTPUT
print @FirstName
print @MiddleName
print @LastName
output:
Scott
The Other Scott
Kowalczyk
至于其他人说,你不能从一个简单的编程方法。
考虑以下示例:
总统“乔治·赫伯特·沃克·布什”(第一中学中间名姓)
总统刺客“约翰·威尔克斯·布斯”(中间名姓)
吉他手“埃迪·范·海伦”(第一个最后最后)
而他的母亲可能叫他爱德华Lodewijk范海伦(中间名姓最后)
著名的漂流者“玛丽·安的夏天”(第一名姓)
新墨西哥州共和党主席 “费尔南多Ç德巴卡”(第一个最后最后最后)
我不知道有关SQL服务器,但在Postgres的你可以这样做:
SELECT
SUBSTRING(fullname, '(\\w+)') as firstname,
SUBSTRING(fullname, '\\w+\\s(\\w+)\\s\\w+') as middle,
COALESCE(SUBSTRING(fullname, '\\w+\\s\\w+\\s(\\w+)'), SUBSTRING(fullname, '\\w+\\s(\\w+)')) as lastname
FROM
public.person
正则表达式的表达或许可以更简洁一点; 但你明白了吧。 这确实的方式用于具有两个双名人员无法正常工作(在荷兰,我们有这个有很多“扬范德Ploeg”),所以我会很小心的结果。
当然,我们都明白,有解决这个问题没有完美的方法,但一些解决方案可以让你比别人更远。
特别是,它是很容易超越简单的空格分离器,如果你只是有共同的前缀(先生,博士,太太等),缀(冯,德,德尔等),后缀(JR,III的某些列表,锶等),等等。 如果你有共同的名字的一些列表(在各种语言/文化,如果你的名字是不同的),它也是有用的,这样你可以猜测在中间的字是否有可能成为最后的名称或没有的部分。
中文提供也实现了一些启发式功能,让你的存在方式的一部分; 他们的包裹在Text::BibTeX::Name
的Perl模块。 下面是做了合理的工作的快速代码示例。
use Text::BibTeX;
use Text::BibTeX::Name;
$name = "Dr. Mario Luis de Luigi Jr.";
$name =~ s/^\s*([dm]rs?.?|miss)\s+//i;
$dr=$1;
$n=Text::BibTeX::Name->new($name);
print join("\t", $dr, map "@{[ $n->part($_) ]}", qw(first von last jr)), "\n";
我碰到了这样做的最大的问题是像“鲍勃·R·史密斯,小”的情况。 我使用的算法公布在http://www.blackbeltcoder.com/Articles/strings/splitting-a-name-into-first-and-last-names 。 我的代码是在C#中,但你可以端口,如果你必须在SQL。
通过@JosephStyons和@Digs的工作是伟大的! 我用自己的作品的部分创建的SQL Server 2016和较新的一个新功能。 这其中也处理后缀,以及前缀。
CREATE FUNCTION [dbo].[NameParser]
(
@name nvarchar(100)
)
RETURNS TABLE
AS
RETURN (
WITH prep AS (
SELECT
original = @name,
cleanName = REPLACE(REPLACE(REPLACE(REPLACE(LTRIM(RTRIM(@name)),' ',' '),' ',' '), '.', ''), ',', '')
)
SELECT
prep.original,
aux.prefix,
firstName.firstName,
middleName.middleName,
lastName.lastName,
aux.suffix
FROM
prep
CROSS APPLY (
SELECT
prefix =
CASE
WHEN LEFT(prep.cleanName, 3) IN ('MR ', 'MS ', 'DR ', 'FR ')
THEN LEFT(prep.cleanName, 2)
WHEN LEFT(prep.cleanName, 4) IN ('MRS ', 'LRD ', 'SIR ')
THEN LEFT(prep.cleanName, 3)
WHEN LEFT(prep.cleanName, 5) IN ('LORD ', 'LADY ', 'MISS ', 'PROF ')
THEN LEFT(prep.cleanName, 4)
ELSE ''
END,
suffix =
CASE
WHEN RIGHT(prep.cleanName, 3) IN (' JR', ' SR', ' II', ' IV')
THEN RIGHT(prep.cleanName, 2)
WHEN RIGHT(prep.cleanName, 4) IN (' III', ' ESQ')
THEN RIGHT(prep.cleanName, 3)
ELSE ''
END
) aux
CROSS APPLY (
SELECT
baseName = LTRIM(RTRIM(SUBSTRING(prep.cleanName, LEN(aux.prefix) + 1, LEN(prep.cleanName) - LEN(aux.prefix) - LEN(aux.suffix)))),
numParts = (SELECT COUNT(1) FROM STRING_SPLIT(LTRIM(RTRIM(SUBSTRING(prep.cleanName, LEN(aux.prefix) + 1, LEN(prep.cleanName) - LEN(aux.prefix) - LEN(aux.suffix)))), ' '))
) core
CROSS APPLY (
SELECT
firstName =
CASE
WHEN core.numParts <= 1 THEN core.baseName
ELSE LEFT(core.baseName, CHARINDEX(' ', core.baseName, 1) - 1)
END
) firstName
CROSS APPLY (
SELECT
remainder =
CASE
WHEN core.numParts <= 1 THEN ''
ELSE LTRIM(SUBSTRING(core.baseName, LEN(firstName.firstName) + 1, 999999))
END
) work1
CROSS APPLY (
SELECT
middleName =
CASE
WHEN core.numParts <= 2 THEN ''
ELSE LEFT(work1.remainder, CHARINDEX(' ', work1.remainder, 1) - 1)
END
) middleName
CROSS APPLY (
SELECT
lastName =
CASE
WHEN core.numParts <= 1 THEN ''
ELSE LTRIM(SUBSTRING(work1.remainder, LEN(middleName.middleName) + 1, 999999))
END
) lastName
)
GO
SELECT * FROM dbo.NameParser('Madonna')
SELECT * FROM dbo.NameParser('Will Smith')
SELECT * FROM dbo.NameParser('Neil Degrasse Tyson')
SELECT * FROM dbo.NameParser('Dr. Neil Degrasse Tyson')
SELECT * FROM dbo.NameParser('Mr. Hyde')
SELECT * FROM dbo.NameParser('Mrs. Thurston Howell, III')
入住雅典娜这个查询只有一个空间分隔的字符串(如名字和中间名的组合):
SELECT name, REVERSE( SUBSTR( REVERSE(name), 1, STRPOS(REVERSE(name), ' ') ) ) AS middle_name FROM name_table
如果您希望有两个或两个以上的空间,你可以轻松地扩展上面的查询。
根据@ hajili的贡献(这是一个创造性的使用PARSENAME功能,旨在解析对象的名称是句点分隔),我修改了它,所以它可以处理情况的数据不containt中间名或当名称为“John和Jane Doe的”。 这不是100%完美,但它的结构紧凑,可以做取决于商业案例的伎俩。
SELECT NAME,
CASE WHEN parsename(replace(NAME, ' ', '.'), 4) IS NOT NULL THEN
parsename(replace(NAME, ' ', '.'), 4) ELSE
CASE WHEN parsename(replace(NAME, ' ', '.'), 3) IS NOT NULL THEN
parsename(replace(NAME, ' ', '.'), 3) ELSE
parsename(replace(NAME, ' ', '.'), 2) end END as FirstName
,
CASE WHEN parsename(replace(NAME, ' ', '.'), 3) IS NOT NULL THEN
parsename(replace(NAME, ' ', '.'), 2) ELSE NULL END as MiddleName,
parsename(replace(NAME, ' ', '.'), 1) as LastName
from {@YourTableName}