51 votes

SQL: analyser le prénom, le prénom et le nom d'un champ de nom complet

Comment dois-je analyser le prénom, second prénom et nom d'un champ nom complet avec SQL?

J'ai besoin d'essayer de faire correspondre les noms qui ne sont pas une correspondance directe sur le nom complet. Je aimerais être en mesure de prendre le nom de domaine et de le diviser en premier, nom et prénom.

Les données n'incluent pas les préfixes ou suffixes. Le deuxième nom est facultatif. Les données sont formatées 'Milieu prénom'.

Je suis intéressé par des solutions pratiques pour me 90% du chemin. Comme il a été dit, c'est un problème complexe, je vais donc répondre à des cas individuellement.

142voto

JosephStyons Points 21187

Voici un exemple, avec le manipuler facilement des données de test.

Avec cet exemple, si vous avez un nom avec plus de trois, puis tous les "extra" les choses vont se mettre dans le NOM de champ. Une exception est faite pour les chaînes qui sont identifiés comme des "titres", comme le "DR", "MADAME" et "MONSIEUR".

Si le prénom est manquant, puis vous obtenez juste FIRST_NAME et LAST_NAME (MIDDLE_NAME sera NULLE).

Vous pourriez écraser en un géant imbriquée blob de sous-Chaînes, mais la lisibilité est assez difficile comme il est lorsque vous faites cela en SQL.

Edit-- Gérer les cas spéciaux suivants:

1 - Le NOM du champ est NULL

2 - Le champ NOM contient leading / trailing spaces

3 - Le NOM de domaine a > 1 consécutifs de l'espace dans le nom

4 - Le NOM de domaine ne contient que le nom de la première

5 - Inclure le nom complet original dans la sortie finale dans une colonne distincte, pour des raisons de lisibilité

6 - Gérer une liste de préfixes comme un "titre" de la colonne

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

10voto

neonski Points 772

Il est difficile de répondre sans savoir comment le "nom complet" n'est pas formaté.

Il peut être "Nom, prénom du Moyen-Nom" ou "prénom deuxième prénom Nom", etc.

Fondamentalement, vous devez utiliser la sous-CHAÎNE de la fonction

SUBSTRING ( expression , start , length )

Et probablement le CHARINDEX fonction

CHARINDEX (substr, expression)

Pour déterminer le début et la durée pour chaque partie que vous voulez extraire.

Donc, disons que le format "prénom Nom", vous pouvez (non testé.. mais devrait être proche) :

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

8voto

Lasse V. Karlsen Points 148037

Inverser le problème, ajouter des colonnes pour tenir les pièces individuelles et de les combiner pour obtenir le nom complet.

La raison de ce qui sera la meilleure réponse est qu'il n'est pas garanti de trouver une personne qui a enregistré leur premier nom, et quel est le nom du milieu.

Par exemple, comment voulez-vous partager ce?

Jan Olav Olsen Heggelien

Ce, tout en étant fictifs, est un nom légal en Norvège, et pourrait, mais pas à, être divisé comme ceci:

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

ou, comme ceci:

First name: Jan Olav
Last name: Olsen Heggelien

ou, comme ceci:

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

J'imagine similaire événements peuvent être trouvés dans la plupart des langues.

Ainsi, au lieu d'essayer de l'interprétation des données qui ne dispose pas de suffisamment d'informations pour obtenir la droite, magasin de la justesse de l'interprétation, et de les combiner pour obtenir le nom complet.

7voto

Josh Millard Points 939

À moins que vous ne possédiez des données très, très sage, il s'agit d'un défi non trivial. Une approche naïve consisterait à définir des espaces et à supposer qu’un résultat de trois indicateurs est [premier, deuxième, dernier] et un résultat de deux indicateurs est un (premier, dernier), mais que vous devrez traiter plusieurs noms de famille de mots (par exemple "Van Buren") et plusieurs prénoms.

3voto

Brice Williams Points 68

Pour une solution gratuite basée sur le CLR SQL, assurez-vous de consulter SqlName de Ambient Concepts, qui peut s'avérer une aide précieuse pour l'analyse des noms au niveau de la base de données.

http://ambientconcepts.com/sqlname

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X