SQL: анализировать имя, отчество и фамилию из поля полного имени - PullRequest
40 голосов
/ 02 октября 2008

Как мне разобрать имя, отчество и фамилию из поля полного имени с помощью SQL?

Мне нужно попытаться сопоставить имена, которые не совпадают с полным именем. Я хотел бы иметь возможность взять поле полного имени и разбить его на имя, отчество и фамилию.

Данные не включают префиксы или суффиксы. Отчество не обязательно. Данные отформатированы как «Первый Средний Последний».

Меня интересуют некоторые практические решения, которые помогут мне пройти 90% пути. Как уже было сказано, это сложная проблема, поэтому я буду разбираться с особыми случаями индивидуально.

Ответы [ 23 ]

130 голосов
/ 02 октября 2008

Вот отдельный пример с легко манипулируемыми данными испытаний.

В этом примере, если у вас есть имя из более чем трех частей, тогда все «лишние» вещи будут помещены в поле LAST_NAME. Исключение сделано для определенных строк, которые определены как «заголовки», такие как «DR», «MRS» и «MR».

Если отчество отсутствует, вы просто получаете FIRST_NAME и LAST_NAME (MIDDLE_NAME будет NULL).

Вы можете разбить его на гигантский вложенный шарик СУБСТРИНГОВ, но читаемость достаточно сложна, как и при работе в SQL.

Редактировать - обрабатывать следующие особые случаи:

1 - поле ИМЯ равно NULL

2 - Поле ИМЯ содержит начальные / конечные пробелы

3 - Поле ИМЯ содержит> 1 последовательный пробел в имени

4 - поле ИМЯ содержит ТОЛЬКО имя

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
8 голосов
/ 02 октября 2008

Трудно ответить, не зная, как отформатировано «полное имя».

Это могут быть «Фамилия, Имя, Отчество» или «Имя, Фамилия, Имя» и т. Д.

В основном вам придется использовать функцию SUBSTRING

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
7 голосов
/ 02 октября 2008

Поменяйте задачу, добавьте столбцы для хранения отдельных частей и объедините их, чтобы получить полное имя.

Причина, по которой это будет лучший ответ, заключается в том, что не существует гарантированного способа выяснить, какое лицо зарегистрировано по имени и каково его второе имя.

Например, как бы вы разбили это?

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

Я полагаю, что подобные случаи встречаются в большинстве языков.

Таким образом, вместо того, чтобы пытаться интерпретировать данные, которые не имеют достаточной информации, чтобы их правильно понять, сохраните правильную интерпретацию и объедините, чтобы получить полное имя.

6 голосов
/ 02 октября 2008

Если у вас нет очень хороших данных, это нетривиальная задача. Наивным подходом было бы разбить токены на пустое пространство и предположить, что результатом с тремя токенами является [первый, средний, последний], а результатом с двумя токенами является [первый, последний], но вам придется иметь дело с несколькими фамилии слов (например, «Ван Бурен») и несколько отчеств.

4 голосов
/ 29 декабря 2015

Альтернативным простым способом является использование 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

источник

3 голосов
/ 08 мая 2011

Для бесплатного решения на основе SQL CLR обязательно ознакомьтесь с SqlName из Ambient Concepts, которое может быть очень полезно при анализе имен на уровне базы данных.

http://ambientconcepts.com/sqlname

2 голосов
/ 02 октября 2008

Вы уверены, что полное юридическое имя всегда будет включать имя, отчество и фамилию? Я знаю людей, которые имеют только одно имя в качестве Полного юридического имени, и, честно говоря, я не уверен, что это их имя или фамилия. :-) Я также знаю людей, которые имеют более одного имени Fisrt в своем официальном названии, но не имеют среднего имени. И есть люди, которые имеют несколько средних имен.

Тогда есть также порядок имен в Полном Юридическом Имени. Насколько я знаю, в некоторых азиатских культурах фамилия стоит на первом месте в полном юридическом названии.

С практической точки зрения вы можете разделить Полное имя на пробел и поставить под угрозу первый токен как Имя и последний токен (или единственный токен в случае только одного имени) как Фамилия. Хотя это предполагает, что порядок всегда будет одинаковым.

1 голос
/ 02 октября 2008

Я бы сделал это как итеративный процесс.

1) Создать таблицу для работы с плоским файлом.

2) Напишите простую программу для разбиения ваших имен, используя пробел в качестве разделителя, где первый токен является первым именем, если имеется 3 токена, то токен 2 - это второе имя, а токен 3 - фамилия. Если есть 2 токена, то второй токен является фамилией. (Perl, Java или C / C ++, язык не имеет значения)

3) Глазное яблоко результаты. Ищите имена, которые не соответствуют этому правилу.

4) Используя этот пример, создайте новое правило для обработки этого исключения ...

5) Промыть и повторить

В конце концов вы получите программу, которая исправит все ваши данные.

1 голос
/ 02 октября 2008

Как сказал # 1, это не тривиально. Фамилии, инициалы, двойные имена, обратная последовательность имен и ряд других аномалий могут испортить вашу тщательно продуманную функцию.

Вы можете использовать стороннюю библиотеку (plug / disclaimer - я работал над этим продуктом):

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

1 голос
/ 08 июля 2016

Это будет работать, если строка является FirstName / MiddleName / LastName

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...