it-swarm.com.de

SQL: Parsen Sie den ersten, den mittleren und den letzten Namen aus einem Feld für vollständige Namen

Wie analysiere ich den ersten, mittleren und letzten Namen aus einem Fullname-Feld mit SQL? 

Ich muss versuchen, Namen zu finden, die nicht direkt mit dem vollständigen Namen übereinstimmen. Ich möchte gerne das vollständige Namensfeld verwenden und es in Vor-, Mittel- und Nachnamen aufteilen. 

Die Daten enthalten keine Präfixe oder Suffixe. Der zweite Vorname ist optional. Die Daten werden als 'First Middle Last' formatiert.

Ich bin an einigen praktischen Lösungen interessiert, um mich zu 90% dort hinzubewegen. Wie gesagt, ist dies ein komplexes Problem, deshalb werde ich Sonderfälle individuell behandeln.

40
Even Mien

Hier ist ein eigenständiges Beispiel mit leicht manipulierbaren Testdaten. 

Wenn Sie in diesem Beispiel einen Namen mit mehr als drei Teilen haben, werden alle zusätzlichen Elemente in das Feld LAST_NAME eingefügt. Eine Ausnahme gilt für bestimmte Zeichenfolgen, die als "Titel" gekennzeichnet sind, wie "DR", "MRS" und "MR".

Wenn der zweite Name fehlt, erhalten Sie nur FIRST_NAME und LAST_NAME (MIDDLE_NAME ist NULL).

Sie könnten es zu einem riesigen verschachtelten Fleck von SUBSTRINGs zerschlagen, aber die Lesbarkeit ist schwer genug, wenn Sie dies in SQL tun.

Bearbeiten-- Behandeln Sie die folgenden Sonderfälle:

1 - Das Feld NAME ist NULL

2 - Das Feld NAME enthält führende/nachgestellte Leerzeichen

3 - Das NAME-Feld enthält> 1 aufeinander folgende Leerzeichen innerhalb des Namens

4 - Das Feld NAME enthält NUR den Vornamen

5 - Füge den ursprünglichen vollständigen Namen in der endgültigen Ausgabe als separate Spalte ein, um die Lesbarkeit zu erleichtern

6 - Behandle eine bestimmte Liste von Präfixen als separate Spalte "Titel"

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
128
JosephStyons

Es ist schwer zu beantworten, ohne zu wissen, wie der "vollständige Name" formatiert ist.

Es könnte "Nachname, Vorname, Vorname" oder "Vorname, Vorname, Nachname" usw. sein.

Grundsätzlich müssen Sie die FunktionSUBSTRINGverwenden

SUBSTRING ( expression , start , length )

Und wahrscheinlich dieCHARINDEXFunktion 

CHARINDEX (substr, expression)

Den Anfang und die Länge jedes zu extrahierenden Teils ermitteln.

Nehmen wir an, das Format ist "Vorname Nachname". 

SELECT 
SUBSTR(fullname, 1, CHARINDEX(' ', fullname) - 1) AS FirstName, 
SUBSTR(fullname, CHARINDEX(' ', fullname) + 1, len(fullname)) AS LastName
FROM YourTable
8
neonski

Kehren Sie das Problem um, fügen Sie Spalten hinzu, um die einzelnen Teile zu speichern, und kombinieren Sie sie, um den vollständigen Namen zu erhalten.

Der Grund für die beste Antwort ist, dass es keinen garantierten Weg gibt, um herauszufinden, ob sich eine Person als Vornamen registriert hat und wie der zweite Vorname ist.

Wie würden Sie das beispielsweise aufteilen?

Jan Olav Olsen Heggelien

Dies ist, obwohl es fiktiv ist, in Norwegen ein gesetzlicher Name und könnte, muss aber nicht so aufgeteilt werden:

First name: Jan Olav
Middle name: Olsen
Last name: Heggelien

oder wie folgt:

First name: Jan Olav
Last name: Olsen Heggelien

oder wie folgt:

First name: Jan
Middle name: Olav
Last name: Olsen Heggelien

Ich könnte mir vorstellen, dass ähnliche Vorkommnisse in den meisten Sprachen zu finden sind.

Statt zu versuchen, Daten zu interpretieren, für die es nicht genügend Informationen gibt, um sie richtig zu machen, speichern Sie die korrekte Interpretation und kombinieren, um den vollständigen Namen zu erhalten.

Wenn Sie nicht über sehr gute Daten verfügen, ist dies eine nicht unbedeutende Herausforderung. Ein naiver Ansatz wäre, den Whitespace zu kennzeichnen und anzunehmen, dass ein Drei-Zeichen-Ergebnis [erster, mittlerer, letzter] und ein zwei-Zeichen-Ergebnis [erster, letzter] ist. Wortnamen (zB "Van Buren") und mehrere zweite Vornamen.

6
Josh Millard

Alternative einfache Art und Weise zu benutzen 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

Quelle

4
hajili

Für eine kostenlose SQL CLR-basierte Lösung sicher sein SqlName von Ambient Konzepten zu überprüfen, was eine große Hilfe beim Parsen Namen auf Datenbankebene sein kann.

http://ambientconcepts.com/sqlname

3
Brice Williams

Sind Sie sicher, dass Sie den vollständigen Namen enthalten immer zuerst, Mitte und Last? Ich kenne Leute, die nur einen Namen als Vollständiger Name der haben, und ehrlich gesagt bin ich nicht sicher, ob das erste oder Nachname ist. :-) Ich kenne auch Leute, die mehr als ein Fisrt Namen in ihren gesetzlichen Namen, aber keine Mittel Namen haben. Und es gibt einige Leute, die mehrere Mittel Namen haben.

Dann gibt es auch die Reihenfolge der Namen in der Vollständiger Name der. Soweit ich weiß, in einigen asiatischen Kulturen der Nachname an erster Stelle in dem Vollständiger Namen der.

Auf praktischer Note, können Sie den vollständigen Name auf Leerzeichen und Bedrohung das erste Token als Vornamen und das letzte Zeichen (oder die einzige Token bei nur einem Namen) als Nachname aufgeteilt. Obwohl dies setzt voraus, dass die Reihenfolge immer gleich sein wird.

2
Franci Penov

Wenn Sie versuchen, einen menschlichen Namen in PHP zu analysieren, empfehle ich das Keith Beckman-Skript nameparse.php .

Kopie für den Fall, dass die Website ausfällt: 

<?
/*
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;
    }


?>
1
Jonathon Hill

Wie # 1 sagte, es ist nicht trivial. Bindestriche letzte Namen, Initialen, Doppelnamen, inverse Namensfolge und eine Vielzahl von anderen Anomalien können Ihre sorgfältig gestaltete Funktion ruinieren.

Sie könnten eine 3rd-Party-Bibliothek verwenden (Stecker/Disclaimer - ich auf diesem Produkt gearbeitet):

http://www.melissadata.com/nameobject/nameobject.htm

1
Marc Bernier

Dies wird im Falle String Arbeit ist Vorname/Middle/Name

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
Nikul

Ich würde dies als iterativen Prozess tun. 

1) Legen Sie die Tabelle in eine flache Datei ab, mit der Sie arbeiten können.

2) Schreiben Sie ein einfaches Programm, um Ihre Namen mit Hilfe eines Leerzeichens als Trennzeichen aufzuteilen, wobei firsts token der erste Name ist. Wenn 3 token vorhanden sind, ist token 2 der zweite Vorname und token 3 der Nachname. Wenn zwei Token vorhanden sind, ist der zweite Token der Nachname. (Sprache Perl, Java oder C/C++ spielt keine Rolle)

3) Betrachte die Ergebnisse. Suchen Sie nach Namen, die dieser Regel nicht entsprechen. 

4) Erstellen Sie in diesem Beispiel eine neue Regel, um diese Ausnahme zu behandeln ...

5) Spülen und wiederholen

Schließlich erhalten Sie ein Programm, das alle Ihre Daten korrigiert.

1
Ben

Ich habe einmal einen regulären Ausdruck mit 500 Zeichen erstellt, um den ersten, letzten und zweiten Namen aus einer beliebigen Zeichenfolge zu analysieren. Selbst mit diesem hupenden Regex erreichte er aufgrund der vollständigen Inkonsistenz der Eingabe nur eine Genauigkeit von 97%. Immer noch besser als nichts.

0
boris

Vorbehaltlich der Einschränkungen, die bereits in Bezug auf Leerzeichen in Namen und anderen Anomalien aufgetreten sind, wird der folgende Code mindestens 98% der Namen verarbeiten. (Hinweis: unordentliches SQL, da ich keine Regex-Option in der von mir verwendeten Datenbank habe.)

** Warnung: Unordentliches SQL folgt:

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

Der Code funktioniert, indem er eine temporäre Tabelle (parsname) erstellt und den vollständigen Namen durch Leerzeichen tokenisiert. Namen, deren Werte in name3 oder name4 enden, sind nicht konform und müssen anders behandelt werden.

0
Kluge

Die Mitarbeitertabelle hat die Spalte "Name" und wir mussten sie in Vor-, Mittel- und Nachnamen aufteilen. Diese Abfrage behandelt es, den zweiten Vornamen als Null zu behalten, wenn die Namensspalte einen Wert von zwei Wörtern wie 'James Thomas' hat.

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
0
Vinay Maurya

Wie alle anderen sagen, kann man das nicht auf eine einfache programmatische Weise machen.

Betrachten Sie diese Beispiele:

  • Präsident "George Herbert Walker Bush" (Erster mittlerer mittlerer Letzter)

  • Mörder des Präsidenten "John Wilkes Booth" (First Middle Last)

  • Gitarrist "Eddie Van Halen" (First Last Last)

  • Und seine Mutter nennt ihn wahrscheinlich Edward Lodewijk Van Halen (First Middle Last Last)

  • Berühmte Castaway "Mary Ann Summers" (First First Last)

  • New Mexico GOP Vorsitzender "Fernando C de Baca"

0
Andy Lester

Diese Abfrage funktioniert einwandfrei.

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
0
Mukesh Pandey

Das größte Problem, dem ich dabei begegnete, waren Fälle wie "Bob R. Smith, Jr.". Der von mir verwendete Algorithmus ist auf http://www.blackbeltcoder.com/Articles/strings/splitting-a-name-into-first-and-last-names zu finden. Mein Code ist in C #, aber Sie könnten ihn portieren, wenn Sie SQL benötigen.

0
Jonathan Wood

Überprüfen Sie diese Abfrage in Athena nur auf eine durch ein Leerzeichen getrennte Zeichenfolge (z. B. Vorname und zweiter Vorname):

SELECT name, REVERSE( SUBSTR( REVERSE(name), 1, STRPOS(REVERSE(name), ' ') ) ) AS middle_name FROM name_table

Wenn Sie zwei oder mehr Leerzeichen erwarten, können Sie die obige Abfrage problemlos erweitern. 

0
James A.

Die Arbeit von @JosephStyons und @Digs ist großartig! Ich habe Teile ihrer Arbeit verwendet, um eine neue Funktion für SQL Server 2016 und neuer zu erstellen. Dieses behandelt auch Suffixe sowie Präfixe.

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')
0
  1. Holen Sie sich eine SQL-Regex-Funktion. Beispiel: http://msdn.Microsoft.com/de-de/magazine/cc163473.aspx
  2. Extrahieren Sie Namen mit regulären Ausdrücken. 

Ich empfehle Expresso zum Lernen/Erstellen/Testen von regulären Ausdrücken. Alte kostenlose Version , neue kommerzielle Version

0
Bartek Szabat

Ich bin nicht sicher über den SQL-Server, aber in Postgres könnte man so etwas machen:

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

Die Regex-Ausdrücke könnten wahrscheinlich etwas prägnanter sein; aber du verstehst den Punkt. Dies funktioniert übrigens nicht für Personen mit zwei Doppelnamen (in den Niederlanden haben wir oft 'Jan van der Ploeg'), also bin ich mit den Ergebnissen sehr vorsichtig.

0
p3t0r

Wir alle wissen natürlich, dass es keine perfekte Lösung für dieses Problem gibt, aber einige Lösungen können Sie weiter bringen als andere. 

Es ist besonders einfach, über einfache Whitespace-Splitter hinauszugehen, wenn Sie nur einige Listen mit gebräuchlichen Präfixen (Herr, Dr., Frau usw.), Infixen (von, de, del, usw.), Suffixen (Jr, III , Sr usw.) und so weiter. Dies ist auch hilfreich, wenn Sie einige Listen mit gebräuchlichen Vornamen haben (in verschiedenen Sprachen/Kulturen, wenn Ihre Namen unterschiedlich sind), sodass Sie erraten können, ob ein Wort in der Mitte wahrscheinlich zum Nachnamen gehört oder nicht.

BibTeX implementiert auch einige Heuristiken, die Ihnen einen Teil des Weges dorthin bringen. Sie sind im Text::BibTeX::Name Perl-Modul eingeschlossen. Hier ist ein kurzer Codebeispiel, das vernünftige Arbeit leistet.

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";
0
Ken Williams

Hier ist eine gespeicherte Prozedur, die das erste gefundene Wort in den Vornamen, das letzte Wort in den Nachnamen und alles dazwischen in den zweiten Vornamen einfügt.

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 

Und hier rufe ich es an.

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
0
Even Mien

Basierend auf dem Beitrag von @ hajili (der eine kreative Verwendung der Funktion parsename ist, die den Namen eines durch Punkte getrennten Objekts analysieren soll), habe ich ihn so geändert, dass er Fälle behandelt, in denen die Daten keinen zweiten Vornamen oder enthalten wenn der Name "John and Jane Doe" ist. Es ist nicht zu 100% perfekt, aber es ist kompakt und kann den Trick je nach Geschäftsfall ausführen.

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}
0
Gustavo Lopez