Bom Dia Pessoal,
Algumas vezes podemos lidar com a necessidade de extrair o primeiro nome e o último nome de uma pessoa. Isso é muito comum em um cadastro de logins de rede, sistema de bilhetagem, etc. Hoje mostrarei duas alternativas para fazer isso.
— Criação da tabela
CREATE TABLE Nomes (Nome VARCHAR(80))
— Inserção de registros
INSERT INTO Nomes VALUES (‘Joana Maria’)
INSERT INTO Nomes VALUES (‘Ana Paula Silveira’)
INSERT INTO Nomes VALUES (‘Pedro Paulo Almeida’)
INSERT INTO Nomes VALUES (‘Carlos Eduardo da Silva’)
INSERT INTO Nomes VALUES (‘Rodrigo Diógenes Cunha Meira’)
INSERT INTO Nomes VALUES (‘Maria’)
A função CHARINDEX retorna a posição de um determinado caractér. Caso o caractér não exista ela retorna zero. Utilizando-se essa função, pode-se obter a posição do espaço e recuperar o primeiro nome.
DECLARE @Nome VARCHAR(100)
SET @Nome = ‘João da Silva Andrade’
SELECT CASE WHEN CHARINDEX(‘ ‘,@Nome) > 0
THEN LEFT(@Nome, CHARINDEX(‘ ‘,@Nome)-1)
ELSE @Nome END As PrimeiroNome
Como a quantidade de nomes pode variar não é possível aplicar uma lógica semelhante para obter o sobrenome, pois, podem haver dois, três, enfim uma quantidade desconhecida de nomes e variável por registro. Uma função que pode ser útil é a função REVERSE. Essa função transforma uma string em seu oposto revertendo-a.
DECLARE @Nome VARCHAR(80)
SET @Nome = ‘João da Silva Andrade’
SELECT REVERSE(@Nome)
Se for observado, a string "edardnA avliS ad oãoJ" é exatamente o oposto da string "João da Silva Andrade" e o primeiro espaço da string "edardnA avliS ad oãoJ" fica na sétima posição. Isso significa que na string "João da Silva Andrade" o último espaço está a 7 posições do final da string. Se ao recuperar o primeiro espaço com a função CHARINDEX e aplicar a função LEFT consegue-se o primeiro nome, aplicando-se a lógica contrária, ou seja, obtendo-se o CHARINDEX do resultado da função REVERSE e aplicando-se a função RIGHT obtêm-se o último nome. É preciso também verificar sempre o valor retornado pelo CHARINDEX, pois, caso não haja o espaço, haverá apenas um único nome e o CHARINDEX retornará zero. Quando isso aconteçe é preciso dar o devido tratamento.
SELECT Nome,
CASE WHEN CHARINDEX(‘ ‘,Nome) > 0
THEN LEFT(Nome, CHARINDEX(‘ ‘,Nome)-1)
ELSE Nome END As PrimeiroNome,
CASE WHEN CHARINDEX(‘ ‘,REVERSE(Nome)) > 0
THEN RIGHT(Nome, CHARINDEX(‘ ‘,REVERSE(Nome))-1)
ELSE ” END As SobreNome
FROM Nomes
Essa é uma alternativa bem interessante, mas como sou adepto de utilizar os novos recursos do T-SQL na versão 2005, gostaria de publicar uma segunda solução. Ao meu ver, poderíamos tratar a string não como pedaços separados por espaço, mas como elementos de um documento XML. Irei utilizar algo bem semelhante a uma das minhas dicas: Como retornar pedaços de um nome composto no SQL Server 2005
Para trabalhar com XML, é necessário converter a string em XML e aplicar os devidos métodos.
DECLARE @Nome VARCHAR(80), @NomeXML XML
SET @Nome = ‘João da Silva Andrade’
SET @NomeXML = ‘<N><n>’ + REPLACE(@Nome,‘ ‘,‘</n><n>’) + ‘</n></N>’
SELECT CAST(@NomeXML.query(‘for $nome in /N return concat($nome/n[1],” ”,$nome/n[last()])’) AS VARCHAR(80))
A conversão para XML transformou a string ‘João da Silva Andrade’ em <N><n>João</n><n>da</n><n>Silva</n><n>Andrade</n></N> que é um documento XML composto de quatro elementos. Para capturar o nome e o sobrenome, basta apenas juntar o primeiro elemento com o último elemento. O método query pôde fazê-lo. Utilizou-se a função concat para concatenar o primeiro nome, um espaço e o último nome. Como o último nome não tem posição fixa, a função last é necessária. O próximo passo é aplicar o comando a todos os registros. Acrescentei as consultas no método XQuery para retornar os nomes separados.
;WITH NomesF (Nome, NomeXML) AS (
SELECT Nome,
CAST(‘<N><n>’ + REPLACE(Nome,‘ ‘,‘</n><n>’) + ‘</n></N>’ AS XML)
FROM Nomes)
SELECT Nome,
CAST(NomeXML.query(
‘for $nome in /N return $nome/n[1]/text()’
) AS VARCHAR(80)) As PrimeiroNome,
CAST(NomeXML.query(
‘for $nome in /N return $nome/n[last()]/text()’
) AS VARCHAR(80)) As SobreNome,
CAST(NomeXML.query(
‘for $nome in /N return concat($nome/n[1],” ”,$nome/n[last()])’
) AS VARCHAR(80)) As NomeAbreviado
FROM NomesF
Acho que essa consulta resolve o mesmo problema através dos novos recursos do SQL Server 2005. Devemos tentar sempre explorar esses recursos, pois, muitas vezes eles abrem novas possibilidades que seriam bem mais difíceis de resolver através de um método mais procedural.
[ ]s,
Gustavo
Não acredito que li isto. O artigo é de separar nome e sobrenome ou de novos recursos? Quem seria o imbecil a transformar uma coluna em xml para quebrar nome e sobrenome? Realmente, ensinando boas práticas! Piada.
Olá João,
Respeito a sua opinião, mas acho que você poderia ser um pouco mais educado em suas colocações. Eu gosto muito de XML, mas não acho que ele seja resposta para tudo. Entretanto não o considero uma implementação imbecil como você classificou. O uso do XML pode ser muito interessante para converter cada pedaço do nome em um registro por exemplo. Supondo um nome composto “João Avela Silva”, o uso do XML pode proporcionar que cada pedaço vire um registro e isso pode ser muito útil em alguns cenários. Você poderia postar uma implementação que julgue mais adequada. Seria de grande valia se pudesse compartilhar algo de mais valor do que o seu hostil comentário.
Não acerto em todas, mas eu me esforço bastante para passar as melhores práticas. Você tem algum blog onde posta implementações ? Gostaria de apreciá-lo.
[ ]s,
Gustavo
Cara parabéns, sou um leitor assíduo dos seus posts e estou estudando muito por eles para este ano completar as certificações de Desenvolvedor e DBA em SQL Server. Espero em breve deixar de ser um mero leitor e poder ser um contribuidor do seu blog. Grande abraço.
Oi Alexandre,
Boa sorte em seus estudos. Espero que o blog possa ajudá-lo bastante.
[ ]s,
Gustavo