将值从一个字段拆分为两个

时间:2010-04-23 07:26:41

标签: mysql split

我有一个表字段membername,其中包含姓氏和用户的名字。是否可以将它们分成2个字段memberfirstmemberlast

所有记录都有这种格式“名字姓氏”(没有引号,中间有空格)。

14 个答案:

答案 0 :(得分:208)

不幸的是,MySQL没有分裂字符串功能。但是,您可以为此创建user defined function,例如以下文章中描述的那个:

使用该功能:

DELIMITER $$

CREATE FUNCTION SPLIT_STR(
  x VARCHAR(255),
  delim VARCHAR(12),
  pos INT
)
RETURNS VARCHAR(255) DETERMINISTIC
BEGIN 
    RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos),
       LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1),
       delim, '');
END$$

DELIMITER ;

您可以按如下方式构建查询:

SELECT SPLIT_STR(membername, ' ', 1) as memberfirst,
       SPLIT_STR(membername, ' ', 2) as memberlast
FROM   users;

如果您不想使用用户定义的函数,并且您不介意查询更冗长,您还可以执行以下操作:

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(membername, ' ', 1), ' ', -1) as memberfirst,
       SUBSTRING_INDEX(SUBSTRING_INDEX(membername, ' ', 2), ' ', -1) as memberlast
FROM   users;

答案 1 :(得分:63)

SELECT变体(不创建用户定义的函数):

SELECT IF(
        LOCATE(' ', `membername`) > 0,
        SUBSTRING(`membername`, 1, LOCATE(' ', `membername`) - 1),
        `membername`
    ) AS memberfirst,
    IF(
        LOCATE(' ', `membername`) > 0,
        SUBSTRING(`membername`, LOCATE(' ', `membername`) + 1),
        NULL
    ) AS memberlast
FROM `user`;

这种方法也需要注意:

  • membername 没有空格的值:它会将整个字符串添加到memberfirst并将memberlast设置为NULL。
  • membername 具有多个空格的值:它会将第一个空格之前的所有内容添加到memberfirst,其余部分(包括其他空格)添加到memberlast。

UPDATE版本将是:

UPDATE `user` SET
    `memberfirst` = IF(
        LOCATE(' ', `membername`) > 0,
        SUBSTRING(`membername`, 1, LOCATE(' ', `membername`) - 1),
        `membername`
    ),
    `memberlast` = IF(
        LOCATE(' ', `membername`) > 0,
        SUBSTRING(`membername`, LOCATE(' ', `membername`) + 1),
        NULL
    );

答案 2 :(得分:20)

如果您的计划是作为查询的一部分执行此操作,执行(a)。说真的,这是一个性能杀手。在某些情况下,您可能不关心性能(例如一次性迁移作业以分割字段以便将来获得更好的性能)但是,如果您经常对除米老鼠数据库之外的任何其他内容执行此操作,则'浪费资源。

如果发现自己必须以某种方式处理部分列,那么您的数据库设计就存在缺陷。它可能适用于家庭地址簿或食谱应用程序或任何其他无数小型数据库,但它不能扩展到“真实”系统。

将名称的组件存储在单独的列中。将列与一个简单的连接(当你需要全名)连接在一起时,通过字符搜索将它们分开,几乎总是快得多。

如果由于某种原因你无法分割字段,至少放入额外的列并使用插入/更新触发器来填充它们。虽然不是3NF,但这将保证数据仍然一致,并将大大加快您的查询速度。您还可以确保额外的列同时具有较低的容量(并且如果您正在搜索它们,则进行索引),以便不必处理案例问题。

而且,如果您甚至无法添加列和触发器,请注意(并让您的客户端知道,如果是客户端),它是不可扩展的。


(a)当然,如果您打算使用此查询修复架构,以便将名称放在表的不同列中而不是查询,我认为这是一个有效的用途。但我重申,在查询中这样做并不是一个好主意。

答案 3 :(得分:15)

现有的回答似乎过于复杂或不是对特定问题的严格回答。

我认为,简单的答案是以下查询:

SELECT
    SUBSTRING_INDEX(`membername`, ' ', 1) AS `memberfirst`,
    SUBSTRING_INDEX(`membername`, ' ', -1) AS `memberlast`
;

我认为在这种特殊情况下没有必要处理超过两个字的名字。如果你想正确地做到这一点,在某些情况下拆分可能非常困难甚至是不可能的:

  • Edgar Allan Poe
  • Johann Wolfgang von Goethe
  • Jakob Ludwig Felix 门德尔松 - 巴托尔迪
  • Lea 门德尔松Bartholdy
  • PetőfiSándor
  • 黒泽

在设计合理的数据库中,人名应存储在部分和整体中。当然,这并不总是可行的。

答案 4 :(得分:7)

使用此

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX( `membername` , ' ', 2 ),' ',1) AS b, 
SUBSTRING_INDEX(SUBSTRING_INDEX( `membername` , ' ', -1 ),' ',2) AS c FROM `users` WHERE `userid`='1'

答案 5 :(得分:5)

不完全回答这个问题,但面对同样的问题,我最终做到了这一点:

UPDATE people_exit SET last_name = SUBSTRING_INDEX(fullname,' ',-1)
UPDATE people_exit SET middle_name = TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(fullname,last_name,1),' ',-2))
UPDATE people_exit SET middle_name = '' WHERE CHAR_LENGTH(middle_name)>3 
UPDATE people_exit SET first_name = SUBSTRING_INDEX(fullname,concat(middle_name,' ',last_name),1)
UPDATE people_exit SET first_name = middle_name WHERE first_name = ''
UPDATE people_exit SET middle_name = '' WHERE first_name = middle_name

答案 6 :(得分:3)

您可能想要这样一个函数的唯一情况是UPDATE查询,它将改变您的表以将Firstname和Lastname存储到单独的字段中。

数据库设计必须遵循某些规则,Database Normalization是最重要的规则之一

答案 7 :(得分:3)

在MySQL中,这是使用此选项:

SELECT Substring(nameandsurname, 1, Locate(' ', nameandsurname) - 1) AS 
       firstname, 
       Substring(nameandsurname, Locate(' ', nameandsurname) + 1)    AS lastname 
FROM   emp  

答案 8 :(得分:1)

我有一个列,其中名字和姓氏都在一列中。第一个和最后一个名字用逗号分隔。下面的代码工作。没有错误检查/纠正。只是一个愚蠢的分裂。使用phpMyAdmin执行SQL语句。

UPDATE tblAuthorList SET AuthorFirst = SUBSTRING_INDEX(AuthorLast,',',-1) , AuthorLast = SUBSTRING_INDEX(AuthorLast,',',1);

13.2.10 UPDATE Syntax

答案 9 :(得分:1)

从这里获取smhg,从Last index of a given substring in MySQL获取curt并将它们组合起来。这是为了mysql,我需要的是将名称分割为first_name last_name,其姓氏为单个单词,名字前面的所有名称,其中名称可以为null,1个单词,2个单词,或者超过2个字。就是:空虚;玛丽;玛丽史密斯;玛丽史密斯; Mary Sue Ellen Smith;

因此,如果name是一个单词或null,则last_name为null。如果名称是> 1个单词,last_name是最后一个单词,first_name是最后一个单词之前的所有单词。

请注意,我已经完成了像Joe Smith Jr.这样的事情。 Joe Smith Esq。等等,手动,当然是痛苦的,但它足够小,所以你想确保在决定使用哪种方法之前真正查看名称字段中的数据。

请注意,这也会减少结果,因此您不会在名称前面或后面留下空格。

我只是为那些可能会在这里寻找我需要的方式谷歌的人发布这个。当然,这可以先用select来测试它。

这是一次性事情,所以我不关心效率。

SELECT TRIM( 
    IF(
        LOCATE(' ', `name`) > 0,
        LEFT(`name`, LENGTH(`name`) - LOCATE(' ', REVERSE(`name`))),
        `name`
    ) 
) AS first_name,
TRIM( 
    IF(
        LOCATE(' ', `name`) > 0,
        SUBSTRING_INDEX(`name`, ' ', -1) ,
        NULL
    ) 
) AS last_name
FROM `users`;


UPDATE `users` SET
`first_name` = TRIM( 
    IF(
        LOCATE(' ', `name`) > 0,
        LEFT(`name`, LENGTH(`name`) - LOCATE(' ', REVERSE(`name`))),
        `name`
    ) 
),
`last_name` = TRIM( 
    IF(
        LOCATE(' ', `name`) > 0,
        SUBSTRING_INDEX(`name`, ' ', -1) ,
        NULL
    ) 
);

答案 10 :(得分:0)

当数据到达first_name字段时,我用于将first_name拆分为first_name和last_name。这将只在姓氏字段中放置最后一个单词,因此" john phillips sousa"将是" john phillips"名字和" sousa"姓。它还避免覆盖已经修复的任何记录。

set last_name=trim(SUBSTRING_INDEX(first_name, ' ', -1)), first_name=trim(SUBSTRING(first_name,1,length(first_name) - length(SUBSTRING_INDEX(first_name, ' ', -1)))) where list_id='$List_ID' and length(first_name)>0 and length(trim(last_name))=0

答案 11 :(得分:0)

UPDATE `salary_generation_tbl` SET
    `modified_by` = IF(
        LOCATE('$', `other_salary_string`) > 0,
        SUBSTRING(`other_salary_string`, 1, LOCATE('$', `other_salary_string`) - 1),
        `other_salary_string`
    ),
    `other_salary` = IF(
        LOCATE('$', `other_salary_string`) > 0,
        SUBSTRING(`other_salary_string`, LOCATE('$', `other_salary_string`) + 1),
        NULL
    );

答案 12 :(得分:0)

如果有人需要遍历表并拆分字段:

  1. 首先我们使用function mention above
CREATE DEFINER=`root`@`localhost` FUNCTION `fn_split_str`($str VARCHAR(800), $delimiter VARCHAR(12), $position INT) RETURNS varchar(800) CHARSET utf8
    DETERMINISTIC
BEGIN 
    RETURN REPLACE(
            SUBSTRING(
                SUBSTRING_INDEX($str, $delimiter, $position),
                LENGTH(
                    SUBSTRING_INDEX($str, $delimiter, $position -1)
                ) + 1
            ),
    $delimiter, '');
END
  1. 第二,我们在字符串上运行while循环,直到没有任何结果(我为JOIN子句添加了$ id):
CREATE DEFINER=`root`@`localhost` FUNCTION `fn_split_str_to_rows`($id INT, $str VARCHAR(800), $delimiter VARCHAR(12), $empty_table BIT) RETURNS int(11)
BEGIN

    DECLARE position INT;
    DECLARE val VARCHAR(800);
    SET position = 1;
    
    IF $empty_table THEN
        DROP TEMPORARY TABLE IF EXISTS tmp_rows;    
    END IF;
            
    SET val = fn_split_str($str, ',', position);
            
    CREATE TEMPORARY TABLE IF NOT EXISTS tmp_rows AS (SELECT $id as id, val as val where 1 = 2);
        
    WHILE (val IS NOT NULL and val != '') DO               
        INSERT INTO tmp_rows
        SELECT $id, val;
        
        SET position = position + 1;
        SET val = fn_split_str($str, ',', position);
    END WHILE;
    
    RETURN position - 1;
END
  1. 最后,我们可以像这样使用它:
DROP TEMPORARY TABLE IF EXISTS tmp_rows;
SELECT  SUM(fn_split_str_to_rows(ID, FieldToSplit, ',', 0))
FROM    MyTable;

SELECT * FROM tmp_rows;

您可以使用ID联接到其他表。

如果您只拆分一个值,则可以像这样使用它

SELECT  fn_split_str_to_rows(null, 'AAA,BBB,CCC,DDD,EEE,FFF,GGG', ',', 1);
SELECT * FROM tmp_rows;

我们不需要清空临时表,该函数将解决该问题。

答案 13 :(得分:-3)

mysql 5.4提供了原生的分割功能:

SPLIT_STR(<column>, '<delimiter>', <index>)