trycast try_parse separar por parse left into delimitada comas cadena sql sql-server tsql parsing

try_parse - SQL: analiza el primer, segundo y segundo nombre de un campo de nombre completo



sql server try_parse (21)

  1. Obtenga una función de expresión regular sql. Muestra: http://msdn.microsoft.com/en-us/magazine/cc163473.aspx
  2. Extrae nombres usando expresiones regulares.

Recomiendo Expresso para aprender / construir / probar expresiones regulares. Antigua versión gratuita , nueva versión comercial

¿Cómo puedo analizar el primer, segundo y último nombre de un campo de nombre completo con SQL?

Necesito tratar de hacer coincidir los nombres que no coinciden directamente con el nombre completo. Me gustaría poder tomar el campo de nombre completo y dividirlo en primer, segundo y segundo nombre.

Los datos no incluyen ningún prefijo o sufijo. El segundo nombre es opcional. Los datos tienen el formato ''First Middle Last''.

Estoy interesado en algunas soluciones prácticas para obtener el 90% del camino hasta allí. Como se ha dicho, este es un problema complejo, por lo que manejaré casos especiales de forma individual.


¡El trabajo de @JosephStyons y @Digs es genial! Utilicé partes de su trabajo para crear una nueva función para SQL Server 2016 y posteriores. Este también maneja los sufijos, así como los prefijos.

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'')


¿Seguro que el Nombre legal completo siempre incluirá Primero, Medio y Último? Conozco personas que solo tienen un nombre como Full Legal Name, y sinceramente no estoy seguro de si ese es su nombre o apellido. :-) También conozco personas que tienen más de un nombre de Fisrt en su nombre legal, pero que no tienen un segundo nombre. Y hay algunas personas que tienen varios nombres medios.

Luego también está el orden de los nombres en el Nombre Legal Completo. Hasta donde yo sé, en algunas culturas asiáticas, el apellido viene primero en el nombre legal completo.

En una nota más práctica, podría dividir el Nombre completo en espacios en blanco y amenazar el primer token como Nombre y el último token (o el único token en el caso de un solo nombre) como Apellido. Aunque esto supone que el orden será siempre el mismo.


A menos que tenga datos muy, muy bien educados, este es un desafío no trivial. Un enfoque ingenuo sería tokenizar en espacios en blanco y asumir que un resultado de tres tokens es [primero, medio, último] y un resultado de dos tokens es [primero, el último], pero vas a tener que lidiar con múltiples apellidos (por ejemplo, "Van Buren") y varios apellidos intermedios.


Aquí hay un ejemplo autónomo, con datos de prueba fácilmente manipulados.

Con este ejemplo, si tiene un nombre con más de tres partes, todas las cosas "adicionales" se incluirán en el campo LAST_NAME. Se hace una excepción para cadenas específicas que se identifican como "títulos", como "DR", "MRS" y "MR".

Si falta el segundo nombre, acaba de obtener FIRST_NAME y LAST_NAME (MIDDLE_NAME será NULL).

Podrías romperlo en una masa gigante anidada de SUBSTRING, pero la legibilidad es lo suficientemente difícil como lo es cuando haces esto en SQL.

Editar-- Maneje los siguientes casos especiales:

1 - El campo NAME es NULL

2 - El campo NAME contiene espacios iniciales / finales

3 - El campo NOMBRE tiene> 1 espacio consecutivo dentro del nombre

4 - El campo NOMBRE contiene SOLAMENTE el primer nombre

5 - Incluye el nombre completo original en el resultado final como una columna separada, para la legibilidad

6 - Manejar una lista específica de prefijos como una columna separada de "título"

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


Aquí hay un procedimiento almacenado que colocará la primera palabra encontrada en Nombre, la última palabra en Apellido y todo lo intermedio en el Segundo nombre.

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

Y aquí estoy yo llamándolo.

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


Como dijo # 1, no es trivial. Los apellidos, iniciales, nombres dobles, secuencia inversa de nombres y una variedad de otras anomalías pueden arruinar su función cuidadosamente diseñada.

Puede utilizar una biblioteca de terceros (plug / disclaimer - He trabajado en este producto):

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


Como todos los demás dicen, no se puede desde una simple forma programática.

Considera estos ejemplos:

  • Presidente "George Herbert Walker Bush" (Primer Medio Medio)

  • Asesino presidencial "John Wilkes Booth" (Primer medio último)

  • Guitarrista "Eddie Van Halen" (Primer Último Último)

  • Y su madre probablemente lo llame Edward Lodewijk Van Halen (Primer medio último)

  • El famoso náufrago "Mary Ann Summers" (First First Last)

  • El presidente del Partido Republicano de Nuevo México, "Fernando C de Baca" (Primero, el último, último)



Es difícil responder sin saber cómo se formatea el "nombre completo".

Podría ser "Apellido, Nombre intermedio del nombre" o "Apellido del segundo nombre", etc.

Básicamente, deberás usar la función SUBSTRING

SUBSTRING ( expression , start , length )

Y probablemente la función CHARINDEX

CHARINDEX (substr, expression)

Para averiguar el inicio y la duración de cada parte que desea extraer.

Así que digamos que el formato es "Nombre Apellido" que podría (no probado ... pero debería estar cerca):

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


Esto funcionará en mayúscula y minúscula es 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


Haría esto como un proceso iterativo.

1) Vuelca la tabla a un archivo plano para trabajar.

2) Escribe un programa simple para dividir tus nombres usando un espacio como separador donde el primer token es token, si hay 3 token, el token 2 es el segundo nombre y el token 3 es el último. Si hay 2 fichas, el segundo token es el apellido. (Perl, Java o C / C ++, el lenguaje no importa)

3) Eyeball los resultados. Busque los nombres que no se ajustan a esta regla.

4) Usando ese ejemplo, crea una nueva regla para manejar esa excepción ...

5) Enjuague y repita

Eventualmente obtendrás un programa que arregla todos tus datos.


Invierta el problema, agregue columnas para contener las piezas individuales y combínelas para obtener el nombre completo.

La razón por la cual esta será la mejor respuesta es que no hay una forma garantizada de descubrir que una persona se ha registrado como su primer nombre, y cuál es su segundo nombre.

Por ejemplo, ¿cómo separarías esto?

Jan Olav Olsen Heggelien

Esto, aunque ficticio, es un nombre legal en Noruega, y podría, pero no debería ser, dividirse así:

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

o así:

First name: Jan Olav Last name: Olsen Heggelien

o así:

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

Me imagino que se pueden encontrar ocurrencias similares en la mayoría de los idiomas.

Por lo tanto, en lugar de tratar de interpretar los datos que no tienen suficiente información para hacerlo bien, almacene la interpretación correcta y combínelos para obtener el nombre completo.


No estoy seguro acerca de SQL Server, pero en Postgres puedes hacer algo como esto:

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

Las expresiones regex probablemente podrían ser un poco más concisas; Pero usted consigue el punto. Por cierto, esto no funciona para las personas que tienen dos nombres dobles (en los Países Bajos tenemos esto mucho ''Jan van der Ploeg'') así que sería muy cuidadoso con los resultados.


Para obtener una solución basada en SQL CLR gratuita, asegúrese de consultar SqlName de Ambient Concepts, que puede ser una gran ayuda para analizar nombres a nivel de base de datos.

http://ambientconcepts.com/sqlname


Por supuesto, todos entendemos que no hay una manera perfecta de resolver este problema, pero algunas soluciones pueden llevarlo más lejos que otros.

En particular, es bastante fácil ir más allá de los simples divisores de espacio en blanco si solo tiene algunas listas de prefijos comunes (Mr, Dr, Mrs, etc.), infijos (von, de, del, etc.), sufijos (Jr, III , Sr, etc.) y así sucesivamente. También es útil si tiene algunas listas de nombres comunes (en varios idiomas / culturas, si sus nombres son diversos) para que pueda adivinar si una palabra en el medio es probable que sea parte del apellido o no.

BibTeX también implementa algunas heurísticas que te llevan a una parte del camino; están encapsulados en el Text::BibTeX::Name perl. Aquí hay una muestra de código rápido que hace un trabajo razonable.

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";


Si intentas analizar un nombre humano en PHP, recomiendo el script nameparse.php de Keith Beckman .

Copie en caso de que el sitio se caiga:

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


Sujeto a las advertencias que ya se han planteado con respecto a los espacios en los nombres y otras anomalías, el siguiente código, al menos, manejará el 98% de los nombres. (Nota: SQL desordenado porque no tengo una opción de expresión regular en la base de datos que uso).

** Advertencia: sigue un desordenado 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

El código funciona creando una tabla temporal (nombre_pars) y tokenizando el nombre completo por espacios. Los nombres que terminan con valores en name3 o name4 no son conformes y deberán tratarse de manera diferente.


Una forma alternativa simple es usar 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

source


Una vez hice una expresión regular de 500 caracteres para analizar primero, último y segundo nombre de una cadena arbitraria. Incluso con esa expresión regular de bocina, solo obtuvo un 97% de precisión debido a la inconsistencia completa de la entrada. Aún así, mejor que nada.


Verifique esta consulta en Athena para una cadena separada de un solo espacio (p. Ej., Primer nombre y combinación de segundo nombre):

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

Si espera tener dos o más espacios, puede extender fácilmente la consulta anterior.