【问题标题】:Splitting a single column (name) into two (forename, surname) in SQL在 SQL 中将单个列(名称)拆分为两个(名字,姓氏)
【发布时间】:2013-12-17 22:18:25
【问题描述】:

目前我正在做一个数据库重新设计项目。该项目的大部分内容是从旧数据库中提取数据并将其导入新数据库。

旧数据库中表中的一列称为“名称”。它在一个字段中包含一个名字和一个姓氏 (ugh)。新表有两列;名字和姓氏。我需要想出一种干净、有效的方法将这一列分成两列。

现在我想在同一张桌子上做所有事情,然后我可以轻松地转移它。

3 列:

  • 姓名(姓名)
  • 名字(目前为空,名字的前半部分应该放在这里)
  • 姓氏(目前为空,姓名的后半部分应放在此处)

我需要做的:将姓名分成两半,并放入姓氏和名字中

如果有人能阐明如何做这种事情,我将不胜感激,因为我以前没有在 SQL 中做过这样的事情。

数据库引擎:MySQL
存储引擎:InnoDB

【问题讨论】:

  • 我认为只要有 sql 标签,stackoverflow 应该询问哪个 rdbms 作为建议标签选项。
  • @ray - 那里的所有答案似乎都是特定于 MSSQL 的,或者需要 MySQL 用户通常无法访问的功能(例如递归 CTE)。
  • 可能是重复的问题? stackoverflow.com/questions/14950466/…
  • @Giupo 是的,可能 - 我还是继续回答了这个问题,因为有很多额外的信息可以提供高质量的答案,而你在那里找不到。

标签: mysql sql


【解决方案1】:

这改进了给出的答案,考虑像“Jack Smith Smithson”这样的条目,如果你只需要名字和姓氏,并且你希望名字是“Jack Smith”和姓氏“Smithson”,那么你需要像这样查询:

-- MySQL

SELECT 
    SUBSTR(full_name, 1, length(full_name) - length(SUBSTRING_INDEX(full_name, ' ', -1)) - 1) as first_name, 
    SUBSTRING_INDEX(full_name, ' ', -1) as last_name 
FROM yourtable

【讨论】:

    【解决方案2】:

    SUBSTRING_INDEX 在 SQL 2018 中对我不起作用,所以我使用了这个:

    declare @fullName varchar(50) = 'First Last1 Last2'
    declare @first varchar(50)
    declare @last varchar(50)
    
    select @last = right(@fullName, len(@fullName)-charindex(' ',@fullName, 1)), @first = left(@fullName, (charindex(' ', @fullName, 1))-1);
    

    产量@first = 'First',@last = 'Last1 Last2'

    【讨论】:

      【解决方案3】:

      对于想要处理全名的人:John -> 名字:John,姓氏:null

      SELECT 
      if( INSTR(`name`, ' ')=0, 
          TRIM(SUBSTRING(`name`, INSTR(`name`, ' ')+1)), 
          TRIM(SUBSTRING(`name`, 1, INSTR(`name`, ' ')-1)) ) first_name,
      if( INSTR(`name`, ' ')=0, 
          null, 
          TRIM(SUBSTRING(`name`, INSTR(`name`, ' ')+1)) ) last_name
      

      John Doe 可以正常工作。但是,如果用户只填写 John 而没有姓氏,SUBSTRING(name, INSTR(name, ' ')+1)) as lastname 将返回 John 而不是 null 并且 firstname 将为 null 并带有 SUBSTRING(name, 1, INSTR(name, ' ')-1)

      在我的例子中,我添加了 if 条件检查以正确确定姓氏并修剪以防止它们之间出现多个空格。

      【讨论】:

        【解决方案4】:

        只是想分享我的解决方案。它也适用于中间名。中间名将添加到名字中。

        SELECT 
        TRIM(SUBSTRING(name,1, LENGTH(name)- LENGTH(SUBSTRING_INDEX(name, ' ', -1)))) AS firstname, 
        SUBSTRING_INDEX(name, ' ', -1) AS lastname
        

        【讨论】:

        • 不知道为什么这会被否决。它工作得很好,并且如上所述将中间名添加到名字并将姓氏保留为姓氏。如果这是所需的行为,那么这将完美地回答它。
        • 请注意,这对于带有变音符号和重音符号的名称会中断,因为“Jürgen”返回的 LENGTH 为 7。请改用 CHAR_LENGTH。
        【解决方案5】:

        从谷歌得到这里,并提出了一个稍微不同的解决方案,它可以处理包含两个以上部分的名称(最多 5 个名称部分,由空格字符创建)。这会将 last_name 列设置为“名字”(第一个空格)右侧的所有内容,还将 full_name 设置为名字部分。也许在运行之前备份您的数据库:-) 但它对我有用:

        UPDATE users SET
         name_last = 	
         CASE
         WHEN LENGTH(SUBSTRING_INDEX(full_name, ' ', 1)) = LENGTH(full_name) THEN ''
         WHEN LENGTH(SUBSTRING_INDEX(full_name, ' ', 2)) = LENGTH(full_name) THEN SUBSTRING_INDEX(del_name, ' ', -1)
         WHEN LENGTH(SUBSTRING_INDEX(full_name, ' ', 3)) = LENGTH(full_name) THEN SUBSTRING_INDEX(del_name, ' ', -2)
         WHEN LENGTH(SUBSTRING_INDEX(full_name, ' ', 4)) = LENGTH(full_name) THEN SUBSTRING_INDEX(del_name, ' ', -3)
         WHEN LENGTH(SUBSTRING_INDEX(full_name, ' ', 5)) = LENGTH(full_name) THEN SUBSTRING_INDEX(del_name, ' ', -4)
         WHEN LENGTH(SUBSTRING_INDEX(full_name, ' ', 6)) = LENGTH(full_name) THEN SUBSTRING_INDEX(del_name, ' ', -5)
        ELSE ''
        END,
        full_name = SUBSTRING_INDEX(full_name, ' ', 1)
        WHERE LENGTH(name_last) = 0 or LENGTH(name_last) is null or name_last = ''

        【讨论】:

          【解决方案6】:

          我遇到了类似的问题,但名称包含多个名称,例如。 “FirstName MiddleNames LastName”,它应该是“MiddleNames”而不是“MiddleName”。

          所以我使用了 substring() 和 reverse() 的组合来解决我的问题:

          select 
              SystemUser.Email, 
              SystemUser.Name, 
              Substring(SystemUser.Name, 1, instr(SystemUser.Name, ' ')) as 'First Name',
              reverse(Substring(reverse(SystemUser.Name), 1, instr(reverse(SystemUser.Name), ' '))) as 'Last Name',
          

          我不需要“中间名”部分,也许这不是解决它的最有效方法,但它对我有用。

          【讨论】:

            【解决方案7】:

            试试这个:

            insert into new_table (forename, lastName, ...)
            select
              substring_index(name, ' ', 1),
              substring(name from instr(name, ' ') + 1),
              ...
            from old_table
            

            这假定第一个单词是名字,其余的是姓氏,这样可以正确处理多单词姓氏,例如“John De Lacey”

            【讨论】:

            • 您知道,您接受的答案有一个潜在的错误;对于像“John De Lacey”这样的宝贝,另一个答案将丢弃除第一个和最后一个单词之外的所有单词。因此 answer 会将第一个单词放入名字列 DVD 中,rest (无论单词有多少)放入 lastName 列,因此不会丢失数据。
            • 谢谢,我明白了,但在这种情况下,“名称”列中的所有内容总是两个词,所以这应该不是问题。
            • 当一个名字只有一个单词时,这会将名字和姓氏设置为同一个东西
            【解决方案8】:

            一个快速的解决方案是使用SUBSTRING_INDEX 获取第一个空格左侧的所有内容,以及第一个空格之后的所有内容:

            UPDATE tablename
            SET
              Forename = SUBSTRING_INDEX(Name, ' ', 1),
              Surname = SUBSTRING_INDEX(Name, ' ', -1)
            

            请看小提琴here。它并不完美,因为一个名称可能有多个空格,但它可能是一个很好的查询开始,它适用于大多数名称。

            【讨论】:

            • 我认为这是我想要的最接近和最简单的方法。感谢发帖!
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-03-26
            • 2020-12-22
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多