2010-04-23 119 views
90

我有一个表字段membername,它包含用户的姓氏和名字。是否有可能将这些分成两个字段memberfirst,memberlast将字段拆分为一个字段

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

+0

“所有记录都有这种格式的”名字姓氏“(不带引号和中间的空格)。” ......奇迹般......请**请**,在做数据库决策时不要忘记像我这样的人。我经常收到网站告诉我,我的姓氏包含一个*非法*(原文如此)的字符...... :( – 2016-06-02 18:53:26

+0

@StijndeWitt你是对的,但是看起来这个数据库似乎不包含你的名字,至少不是在我的国家姓是先写的,所以我也应该在这个数据表中“歧视”,看到这个 - > – 2018-02-07 15:55:25

回答

184

不幸的是,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

它再次出现:) – nomistic 2015-04-29 14:35:49

+0

这个问题的很好的解决方案! – Bergkamp 2015-05-11 12:49:07

+0

仍然不能将IN用作来自该分割操作的“数组值”? – Miguel 2016-09-08 15:39:58

4

,你可能希望这样的功能的唯一情况是一个UPDATE查询,它将改变你的表来存储Firstname和Lastname到不同的字段。

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

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' 
+0

你能解释一下吗? – commonpike 2012-04-13 10:53:24

+0

这将从字段中获取第一个和最后一个空格分隔的子字符串,这在任何情况下都不起作用。例如,如果姓名字段是“Lilly von Schtupp”,那么您将得到'Lilly','Schtupp'作为姓,姓。 – 2012-07-02 20:32:36

19

如果你的计划是做到这一点的查询的一部分,不要” t那么做(a)。严重的是,这是一个性能杀手。在某些情况下,您不关心性能(例如一次性迁移作业将字段拆分,以便将来可以获得更好的性能),但是,如果您经常为除米老鼠数据库以外的任何其他目的执行此操作,则您浪费资源。

如果你有有史以来发现自己不得不以某种方式处理某一列的一部分,你的数据库设计是有缺陷的。它可能适用于家庭地址簿或配方应用程序或任何其他小型数据库,但它不会扩展到“真实”系统。

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

如果出于某种原因无法拆分字段,至少应放入额外的列并使用插入/更新触发器来填充它们。虽然不是3NF,但这将保证数据仍然一致,并将大大加快查询速度。您还可以确保额外的列在同一时间是较小的(并且如果您正在搜索它们,则编入索引),从而无需摆弄案件问题。

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


(一)当然,如果你的目的是使用该查询修复架构,以便名字被放入单独的列在而非查询,我认为这是一个有效的用途。但我重申,在查询中这样做并不是一个好主意。

+4

有时候,你必须这样做。 F.E.我需要一个移植脚本,所以我不关心表演。 – 2013-11-05 11:13:10

+1

你甚至读过这个问题吗? – dfmiller 2014-09-11 16:17:12

+0

@dfmiller,是的,我做了,因此我的理由和详细的回应,并感谢您的兴趣。如果你对我写的东西有特定的问题,请指出,我会看看它是否可以改进。如果这确实是你的意图,那么你现在的评论对于改善情况几乎没有用处。或者,也许你只是在网上发布随机评论,很难说:-)我支持答案,当然,分栏访问是不可扩展的,几乎总是一个坏主意,除非它用于实际上是_fixing_分栏访问。 – paxdiablo 2014-09-12 01:47:26

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 
47

如果你不想使用的功能,此查询处理的事情比清洁其他答案:

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

相比其他答案这种方法需要照顾:

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

更新版本将是:

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 
    ); 
+0

哇!很好。谢谢。 – Pons 2013-03-27 22:42:55

+0

优秀。解决了我的问题。 – Aris 2014-01-14 15:04:06

+0

惊人! thankyou – 2015-10-20 05:42:04

-3

的MySQL 5.4提供了一个天然的分割功能:

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

您能否提供文档链接? dev.mysql.com的搜索结果变干了。 12.5节在这个功能的评论中确实有一个社区建议。 – DRaehal 2013-07-02 22:21:09

1

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

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

13.2.10 UPDATE Syntax

1

这需要从这里生硬的smhg从Last index of a given substring in MySQL,并结合他们。这是用于mysql的,我所需要的只是将姓氏的名称拆分为first_name last_name,姓氏单个单词,第一个名称在单个单词之前,名称可以为null,1个单词,2个单词或超过2个字。即:空;玛丽;玛丽史密斯;玛丽A.史密斯;玛丽苏埃伦史密斯;

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

请注意,我已经削减了像乔史密斯这样的东西;乔史密斯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 
    ) 
); 
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 
6

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

我认为,答案很简单,下面的查询:

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

我认为这是没有必要应对这种特殊情况下更比双字名。如果你想要做正确的,拆分可以在某些情况下是非常困难甚至是不可能的:

  • 埃德加·爱伦·
  • 约翰·沃尔夫冈·冯·歌德
  • 雅各布·路德维希·费利克斯门德尔松·巴托尔迪
  • LEA 门德尔松
  • Pe的TOFI的Sándor
  • 黒泽

在设计合理的数据库,人的名字应该被同时存储在零部件和整体。当然,这并非总是可行的。

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