【问题标题】:Splitting a Full Name into First and Last Name将全名拆分为名字和姓氏
【发布时间】:2017-08-30 21:33:41
【问题描述】:

我有一个全名的客户列表。 我想创建一个以全名作为参数并分别返回名字和姓氏的函数。如果这不可能,我可以有两个单独的函数,一个返回名字,另一个返回姓氏。全名列表包含最多三个单词的名称。 我想要的是这样的:-

  • 当全名由两个单词组成时。第一个应该是 名字和第二个应该是姓氏。
  • 当全名由三个单词组成时。第一个和中间的单词应该是名字,而第三个单词应该是姓氏。

例子:-

**Full Name**    
John Paul White    
Peter Smith    
Ann Marie Brown    
Jack Black    
Sam Olaf Turner

结果:-

**First Name    Last Name**    
John Paul     White    
Peter         Smith      
Ann Marie     Brown    
Jack          Black    
Sam Olaf      Turner

我已经搜索并找到了无法按预期工作的解决方案,并希望得到一些建议。

【问题讨论】:

  • 只要你知道这些规则会将名字分成两部分,不一定是“名字”和“姓氏”,这只是寻找和选择正确的空间和然后将字符串一分为二。如果您的要求是选择正确的空间来找到正确的名字和姓氏,天哪,天哪,您是不是在寻找范围蠕变的惊喜。将名字解析成正确的部分是一项不可能完成的任务,因为一个人认为他的名字和姓氏可能与另一个人不同,即使他们放在一起时具有相同的“全名”。
  • 合乎逻辑的选择应该是为 first、middle、last 等设置不同的字段,让有名字的人决定去哪里。

标签: sql sql-server tsql


【解决方案1】:

保持简短和简单

DECLARE @t TABLE(Fullname varchar(40))
INSERT @t VALUES('John Paul White'),('Peter Smith'),('Thomas')

SELECT
  LEFT(Fullname, LEN(Fullname) - CHARINDEX(' ', REVERSE(FullName))) FirstName,
  STUFF(RIGHT(FullName, CHARINDEX(' ', REVERSE(FullName))),1,1,'') LastName
FROM
  @t

结果:

FirstName  LastName
John Paul  White
Peter      Smith
Thomas     NULL

【讨论】:

    【解决方案2】:

    如果您确定您的姓名将只有两个或三个单词,并且带有单个空格,那么我们可以依靠基本字符串函数来提取名字和姓氏组件。

    SELECT
        CASE WHEN LEN(col) = LEN(REPLACE(col, ' ', '')) + 2
             THEN SUBSTRING(col, 1,
                            CHARINDEX(' ', col, CHARINDEX(' ', col) + 1) - 1)
             ELSE SUBSTRING(col, 1, CHARINDEX(' ', col) - 1)
        END AS first,
        CASE WHEN LEN(col) = LEN(REPLACE(col, ' ', '')) + 2
             THEN SUBSTRING(col,
                            CHARINDEX(' ', col, CHARINDEX(' ', col) + 1) + 1,
                            LEN(col) - CHARINDEX(' ', col, CHARINDEX(' ', col)))
             ELSE SUBSTRING(col,
                            CHARINDEX(' ', col) + 1,
                            LEN(col) - CHARINDEX(' ', col))
        END AS last
    FROM yourTable;
    

    糟糕,但它似乎有效。我的感觉是你应该在某个时候修复你的数据模型。清理您的姓名数据的更理想位置是在数据库之外,例如在爪哇。或者,更好的是,修复数据源,以便从一开始就记录正确的名字和姓氏。

    演示在这里:

    Rextester

    【讨论】:

      【解决方案3】:

      另一个选择(只是为了好玩)是使用一点 XML 与 CROSS APPLY

      示例

      Select FirstName = ltrim(reverse(concat(Pos2,' ',Pos3,' ',Pos4,' ',Pos5)))
            ,LastName  = reverse(Pos1)
       From  YourTable A
       Cross Apply (
                      Select Pos1 = xDim.value('/x[1]','varchar(max)')
                            ,Pos2 = xDim.value('/x[2]','varchar(max)')
                            ,Pos3 = xDim.value('/x[3]','varchar(max)')
                            ,Pos4 = xDim.value('/x[4]','varchar(max)')
                            ,Pos5 = xDim.value('/x[5]','varchar(max)')
                      From  (Select Cast('<x>' + replace(reverse(A.[Full Name]),' ','</x><x>')+'</x>' as xml) as xDim) XMLData
                   ) B
      

      退货

      FirstName               LastName
      John Paul               White
      Peter                   Smith
      Ann Marie               Brown
      Jack                    Black
      Sam Olaf                Turner
                              Cher
      Sally Anne Bella Donna  Baxter
      

      【讨论】:

        【解决方案4】:

        你试图同时做两件事......我不会为你解决问题,但这是我要采取的方向:

        1) 检查字符串拆分:https://ole.michelsen.dk/blog/split-string-to-table-using-transact-sql.html。这将允许您将名称解析为临时表,您可以对其执行逻辑以根据您的规则创建名称

        2) 将此创建为表值函数,以便您可以从参数返回单行解析的 FirstName、LastName。这样您就可以加入它并包含在您的结果中

        【讨论】:

          【解决方案5】:

          您是否尝试过使用 PARSENAME 函数?

          将全名拆分为相应的名字和姓氏的最后一种方法是使用 PARSENAME 字符串函数,从以下脚本可以看出:

              DECLARE @FullName VARCHAR(100)
              SET @FullName = 'John White Doe'
          
              SELECT CONCAT(PARSENAME(REPLACE(@FullName, ' ', '.'), 3),' ',PARSENAME(REPLACE(@FullName, ' ', '.'), 2)) AS [FirstName],
            PARSENAME(REPLACE(@FullName, ' ', '.'), 1) AS [LastName]
          

          欲了解更多信息,请转到此Site

          这是输出..

          【讨论】:

          • 返回“Paul”和“White”并失去“John”。以防万一有人误会PARSENAME 用于解析点分隔的对象名称,例如MyDB.dbo.MyTable - 而不是人名。
          • @MartinSmith 该功能是面向未来的,一旦我们用完社会安全号码,每个人的名字都将基于基于域空间点的命名系统。我的名字是 norway.telemark.porsgrunn.lasse.vågsæther.karlsen,然后这个功能就完美了!直到我们开始殖民行星。永远不要忘记移动。
          • 对不起,Martin 现在我已经更正了那件事。你可以在这个SQL server compiler查看它
          • 脚本输入不正确@FullName = 'John White'
          【解决方案6】:

          使其成为表值函数。

          请参阅here 了解示例

          这是创建函数所需的代码。基本上你只需要拆分你的 LastName

          IF OBJECT_ID(N'dbo.ufnParseName', N'TF') IS NOT NULL
              DROP FUNCTION dbo.ufnParseName;
          GO
          CREATE FUNCTION dbo.ufnParseName(@FullName VARCHAR(300))
          RETURNS @retParseName TABLE 
          (
          -- Columns returned by the function    
          FirstName nvarchar(150) NULL,  
          LastName nvarchar(50) NULL
          )
          AS 
          -- Returns the spliced last name.
          BEGIN
          
               DECLARE 
                  @FirstName nvarchar(250),
                  @LastName nvarchar(250);
              -- Get common contact information
          
              SELECT @LastName = RTRIM(RIGHT(@FullName, CHARINDEX(' ', REVERSE(@FullName)) - 1));
              SELECT @FirstName = LTRIM(RTRIM(Replace(@FullName, @LastName, '')))
          
               INSERT @retParseName
                  SELECT @FirstName, @LastName;
          
              RETURN;
          END
          

          你可以使用SELECT * FROM dbo.ufnParseName('M J K');运行

          为什么是表值函数

          你可以摆脱重复的sql查询,实现DRY

          【讨论】:

            【解决方案7】:

            您可以尝试以下查询。它是根据您的要求编写的,它只处理包含 2 或 3 个部分的 full_name。

            ;WITH cte AS(
                SELECT full_name, (LEN(full_name) - LEN(REPLACE(full_name, ' ', '')) + 1) AS size FROM @temp
                )
            
            SELECT FirstName = 
                CASE 
                    WHEN size=3 THEN PARSENAME(REPLACE(full_name, ' ', '.'), 3) + ' ' + PARSENAME(REPLACE(full_name, ' ', '.'), 2)
                    ELSE PARSENAME(REPLACE(full_name, ' ', '.'), 2)
                END,
                PARSENAME(REPLACE(full_name, ' ', '.'), 1) AS LastName
            FROM cte
            

            【讨论】:

            • 这似乎并不比我的回答简单。它也处理 1 部分名称,将 1 部分放在姓氏中
            • @t-clausen.dk 是的,你的更简单。很抱歉在提交我的之前没有看到你的。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-06-16
            • 1970-01-01
            • 1970-01-01
            • 2014-07-23
            • 1970-01-01
            • 1970-01-01
            • 2013-03-26
            相关资源
            最近更新 更多