SQL: 전체 이름 필드에서 이름, 중간 및 성을 구문 분석합니다.
SQL을 사용하여 전체 이름 필드의 이름, 중간 및 성을 구문 분석하려면 어떻게 해야 합니까?
저는 전체 이름과 직접 일치하지 않는 이름을 맞추려고 노력해야 합니다.풀 네임 필드를 선택해서 이름, 중간, 성으로 나눌 수 있으면 좋겠습니다.
데이터에 접두사나 접미사가 없습니다.가운데 이름은 선택사항입니다.데이터 형식은 'First Middle Last'입니다.
90%까지 갈 수 있는 실용적인 해결책에 관심이 있습니다.말씀드린 것처럼 이 문제는 복잡한 문제이기 때문에 특별한 경우는 개별적으로 처리하도록 하겠습니다.
다음은 테스트 데이터를 쉽게 조작할 수 있는 자체적인 예입니다.
이 예에서 파트가 세 개 이상인 이름이 있을 경우 모든 "추가" 항목이 LAST_NAME 필드에 입력됩니다."DR", "MRS" 및 "MR"과 같이 "타이틀"로 식별되는 특정 문자열에 대해서는 예외로 합니다.
중간 이름이 없으면 FIRST_NAME과 LAST_NAME만 얻을 수 있습니다(MIDLE_NAME은 NULL이 됩니다).
SUBSRING의 거대한 중첩 블롭으로 스매싱할 수 있지만 SQL에서 이 작업을 수행할 때와 마찬가지로 가독성이 충분히 어렵습니다.
편집 -- 다음 특수한 경우를 처리합니다.
1 - NAME 필드가 NULL입니다.
2 - NAME 필드에는 선행/후행 공백이 포함됩니다.
3 - NAME 필드는 이름 내에 1개 이상의 연속된 공백을 갖습니다.
4 - NAME 필드에 이름만 포함됩니다.
5 - 가독성을 위해 최종 출력물에 원래의 전체 이름을 별도의 열로 포함합니다.
6 - 접두사 목록을 별도의 "title" 열로 취급
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
다른 간단한 방법은 다음을 사용하는 것입니다.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
"전체 이름"의 형식을 모르는 상태에서 대답하기는 어렵습니다.
"Last Name, First Name Middle Name" 또는 "First Name Middle Name Last" 등일 수 있습니다.
기본적으로 서브스트링 기능을 사용해야 합니다.
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
저는 대부분의 언어에서 비슷한 현상을 발견할 수 있다고 생각합니다.
따라서 정보가 충분하지 않은 데이터를 정확하게 해석하기 위해 노력하는 대신 정확한 해석을 저장하고 전체 이름을 얻기 위해 결합합니다.
매우, 매우 잘 작동하는 데이터가 없는 한, 이것은 사소한 문제가 아닙니다.순진한 접근 방식은 공백에서 토큰화하여 세 개의 토큰 결과를 [처음, 중간, 마지막]으로 가정하고 두 개의 토큰 결과를 [처음, 마지막]으로 가정하는 것입니다. 하지만 여러 단어의 성(예: "Van Buren")과 여러 개의 중간 이름을 다루어야 합니다.
이 쿼리는 정상적으로 작동합니다.
SELECT name
,Ltrim(SubString(name, 1, Isnull(Nullif(CHARINDEX(' ', name), 0), 1000))) AS FirstName
,Ltrim(SUBSTRING(name, CharIndex(' ', name), CASE
WHEN (CHARINDEX(' ', name, CHARINDEX(' ', name) + 1) - CHARINDEX(' ', name)) <= 0
THEN 0
ELSE CHARINDEX(' ', name, CHARINDEX(' ', name) + 1) - CHARINDEX(' ', name)
END)) AS MiddleName
,Ltrim(SUBSTRING(name, Isnull(Nullif(CHARINDEX(' ', name, Charindex(' ', name) + 1), 0), CHARINDEX(' ', name)), CASE
WHEN Charindex(' ', name) = 0
THEN 0
ELSE LEN(name)
END)) AS LastName
FROM yourtableName
전체 법적 이름에 항상 첫 번째, 중간 및 마지막이 포함되어 있습니까?저는 전체 법적 이름으로 하나의 이름만 있는 사람들을 알고 있는데, 솔직히 그것이 그들의 이름인지 성인지 잘 모르겠습니다. :-) 저는 법적 이름에 둘 이상의 성을 가지고 있지만 중간 이름이 없는 사람들도 알고 있습니다.Middle 이름을 여러 개 가지고 있는 사람들도 있습니다.
그리고 전체 법적 이름에 이름의 순서도 있습니다.제가 아는 한, 일부 아시아 문화권에서는 성이 법적 이름 전체에서 첫 번째로 나옵니다.
좀 더 실용적인 참고에서는 공백의 전체 이름을 분할하고 첫 번째 토큰을 First name(이름)으로 위협하고 마지막 토큰(또는 하나의 이름만 있는 경우에는 유일한 토큰)을 Last name(성)으로 위협할 수 있습니다.이것은 항상 같은 순서일 것이라고 가정합니다.
여기에 첫 번째 단어를 First Name에, 마지막 단어를 Last Name에, 그리고 그 사이의 모든 것을 Middle Name에 넣을 저장 프로시저가 있습니다.
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
문자열이 이름/중간 이름/성인 경우에 작동합니다.
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
#1이 말한 것처럼 사소한 것이 아닙니다.하이픈으로 연결된 성, 이니셜, 이중 이름, 역 이름 순서 및 기타 다양한 이상 징후가 주의 깊게 조작된 기능을 망칠 수 있습니다.
타사 라이브러리를 사용할 수 있습니다(플러그/거부자 - 이 제품에 대해 작업했습니다).
http://www.melissadata.com/nameobject/nameobject.htm
저는 이것을 반복적인 과정으로 하겠습니다.
1) 작업할 플랫 파일에 테이블을 덤프합니다.
2) firsts token이 이름인 구분자로 공백을 사용하여 이름을 분할하는 간단한 프로그램을 작성합니다. 만약 3개의 토큰이 있다면 토큰 2는 중간 이름이고 토큰 3은 성입니다.토큰이 2개일 경우 두 번째 토큰은 성입니다. (Perl, Java 또는 C/C++ 언어는 상관없습니다.)
3) 결과를 눈 여겨 보세요.이 규칙에 맞지 않는 이름을 찾습니다.
4) 이 예를 사용하여 해당 예외를 처리할 새 규칙을 만듭니다.
5) 헹구고 반복하기
결국 모든 데이터를 수정할 수 있는 프로그램을 얻게 될 것입니다.
PHP에서 사람 이름을 파싱하려고 한다면 Keith Beckman의 name parse를 추천합니다.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;
}
?>
- sql regex 함수를 가져옵니다.샘플: http://msdn.microsoft.com/en-us/magazine/cc163473.aspx
- 정규식을 사용하여 이름을 추출합니다.
정규식 학습/구축/테스트를 위해 Express를 추천합니다.이전 무료 버전, 새로운 상용 버전
저는 임의의 문자열에서 이름, 성, 중간 이름을 파싱하기 위해 500자의 정규식을 만든 적이 있습니다.그 경적이 울리더라도 입력의 완전한 불일치로 인해 약 97%의 정확도를 얻는데 그쳤습니다.그래도 없는 것보다는 낫습니다.
이름의 공백 및 기타 이상과 관련하여 이미 제기된 주의 사항에 따라 다음 코드는 적어도 98%의 이름을 처리합니다.(참고: 사용하는 데이터베이스에 regex 옵션이 없기 때문에 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)을 만들고 공백으로 전체 이름을 토큰화하여 작동합니다.name3 또는 name4 값으로 끝나는 모든 이름은 적합하지 않으므로 다르게 처리해야 합니다.
다른 모든 사람들이 말하듯이, 당신은 단순한 프로그램 방식에서 벗어날 수 없습니다.
예를 들어 다음과 같습니다.
대통령 "조지 허버트 워커 부시" (마지막 첫 중간)
대통령 암살자 "존 윌크스 부스" (마지막 첫번째 중간)
기타리스트 "에디 반 헤일런" (First Last)
그리고 그의 엄마는 아마 그를 에드워드 로데바이크 반 헤일런이라고 부를 것입니다. (마지막 첫 중간)
유명한 캐스트웨이 "메리 앤 서머스" (퍼스트 퍼스트 라스트)
뉴멕시코 GOP 의장 '페르난도 C 데 바카'(Fernando C de Baca) (First Last Last)
SQL 서버에 대해서는 잘 모르지만 포스트그레스에서는 다음과 같은 작업을 수행할 수 있습니다.
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
정규 표현식이 좀 더 간결할 수도 있겠지만 요점을 이해합니다.하지만 이것은 두 개의 이중 이름을 가진 사람들에게는 통하지 않기 때문에(네덜란드에서는 이 'Jan van der Ploeg'가 많이 있습니다) 결과에 매우 신중할 것입니다.
물론 우리 모두는 이 문제를 해결할 완벽한 방법이 없다는 것을 이해하지만, 몇몇 솔루션은 다른 솔루션보다 더 멀리 갈 수 있습니다.
특히 일반 접두사(Mr, Dr, Mrs 등), 접미사(Jr, III, Sr 등) 등의 일부 목록만 있으면 단순한 공백 분할을 넘어서기가 꽤 쉽습니다.중간에 있는 단어가 성씨의 일부가 될 가능성이 있는지 아닌지 추측할 수 있도록 일반적인 이름 목록을 가지고 있는 경우(다양한 언어/문화권에서 이름이 다양한 경우)에도 도움이 됩니다.
휴리스틱을 구현하여 는 BibTeX 합니다 이러한 기능은 다음과 같이 캡슐화되어 있습니다.Text::BibTeX::Name
펄 모듈. 인 작업을할 수 여기 합리적인 작업을 수행하는 빠른 코드 샘플이 있습니다.
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')
Athena에서 하나의 공백으로 구분된 문자열(예: 이름과 중간 이름 조합)에 대해서만 이 쿼리를 확인합니다.
SELECT name, REVERSE( SUBSTR( REVERSE(name), 1, STRPOS(REVERSE(name), ' ') ) ) AS middle_name FROM name_table
공백이 두 개 이상일 것으로 예상되는 경우 위 쿼리를 쉽게 확장할 수 있습니다.
@hajili의 기여(주기로 구분된 객체의 이름을 파싱하기 위한 파르세임 함수의 창의적인 사용)를 바탕으로 데이터에 중간 이름이 포함되어 있지 않거나 이름이 "John and Jane Do"인 경우를 처리할 수 있도록 수정했습니다.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}
직원 테이블에 "이름" 열이 있어서 First, Middle, Last Name으로 나누어야 했습니다.이름 열에 'James Thomas'와 같은 두 단어의 값이 있는 경우 이 쿼리는 중간 이름을 null로 유지하도록 처리합니다.
UPDATE Employees
SET [First Name] = CASE
WHEN (len(name) - len(Replace(name, '.', ''))) = 2
THEN PARSENAME(Name, 3)
WHEN (len(name) - len(Replace(name, '.', ''))) = 1
THEN PARSENAME(Name, 2)
ELSE PARSENAME(Name, 1)
END
,[Middle Name] = CASE
WHEN (len(name) - len(Replace(name, '.', ''))) = 2
THEN PARSENAME(Name, 2)
ELSE NULL
END
,[Last Name] = CASE
WHEN (len(name) - len(Replace(name, '.', ''))) = 2
THEN PARSENAME(Name, 1)
WHEN (len(name) - len(Replace(name, '.', ''))) = 1
THEN PARSENAME(Name, 1)
ELSE NULL
END GO
UPDATE Employee
SET [Name] = Replace([Name], '.', ' ') GO
hajili의 제안에 대한 업데이트를 게시하고 싶었지만, 해당 제안에 대한 댓글을 달기에는 이 응답이 너무 깁니다.
우리의 문제는 "성, 이름 중간 이름"이었고 성에 공백이 있었습니다.
그래서 우리는 다음과 같이 생각했습니다.
,FullName = CUST.FULLNAME
,LastName = PARSENAME(REPLACE(CUST.FULLNAME, ',', '.'),2)
,FirstName = (CASE WHEN PARSENAME(REPLACE(CUST.FULLNAME, ',', '.'),1) LIKE '% %' THEN PARSENAME(REPLACE(PARSENAME(REPLACE(CUST.FULLNAME, ',', '.'),1), ' ', '.'),2) ELSE PARSENAME(REPLACE(CUST.FULLNAME, ',', '.'),1) END)
,MiddleName = (CASE WHEN PARSENAME(REPLACE(CUST.FULLNAME, ' ', '.'),1) LIKE '%,%' THEN NULL ELSE PARSENAME(REPLACE(CUST.FULLNAME, ' ', '.'),1) END)
SELECT SUBSRING_INDEX(name, ', 1)를 fname으로, SUBSRING_INDEX(name, ', 2), ', ', -1)를 mname으로, SUBSRING_INDEX(name, ', ', -1)를 lname FROM Person으로 선택합니다.
"전체 이름" 열이 "마지막, 처음 - 중간" 형식인 경우(일반적으로 그렇지 않지만, 그렇다고 가정해 보겠습니다), 이렇게 하면 됩니다.My SQL에서 완료했습니다.첫 번째 행에서 "inner" SUBSTRING_INDEX()는 왼쪽부터 "-", 즉 "Last, First"까지 모든 것을 가져옵니다. 그런 다음 "outer" SUBSTRING_INDEX()는 오른쪽부터 ","까지 모든 것을 이 새로운 "Last, First" 문자열인 "First"까지 가져옵니다.두 번째 줄은 오른쪽에서 '-', 즉 'Middle'까지 작품을 가져옵니다.세 번째 줄은 왼쪽에서 ', '까지 첫 번째 문자열을 가져옵니다.
SUBSTRING_INDEX(SUBSTRING_INDEX(fullname, ' - ', 1), ', ', -1) AS First,
SUBSTRING_INDEX(fullname, ' - ', -1), AS Middle,
SUBSTRING_INDEX(fullname, ', ', 1) AS Last,
Name,
Case when (DATALENGTH(NAME)-DATALENGTH(REPLACE(NAME,' ','')))=2 then
SUBSTRING(Name,CharIndex(' ',NAME,(CharIndex(' ',NAME)+1)),LEN(NAME))
else
SUBSTRING(Name_Line1,CharIndex(' ',NAME,(CharIndex(' ',NAME))),LEN(NAME))
end As Last_name,
Case when (DATALENGTH(NAME)-DATALENGTH(REPLACE(NAME,' ','')))=2 then
SUBSTRING(Name,CharIndex(' ',NAME,(CharIndex(' ',NAME))),(CharIndex(' ',NAME)+1))
else ''
end As Middle_name
언급URL : https://stackoverflow.com/questions/159567/sql-parse-the-first-middle-and-last-name-from-a-fullname-field
'programing' 카테고리의 다른 글
Spring Boot 애플리케이션에서 베어러 인증을 활성화하는 방법은? (0) | 2023.10.11 |
---|---|
마스터의 GTID가 슬레이브와 다를 경우 어떻게 경고를 받을 수 있습니까? (0) | 2023.10.11 |
phphmyadmin을 사용하여 캐스케이드 삭제 및 업데이트 제한에 추가하는 방법은? (0) | 2023.10.11 |
사용자에게 UIView가 보이는지 확인합니다. (0) | 2023.10.11 |
헤더 파일의 정적 인라인 함수 (0) | 2023.10.11 |