2010-04-23 2 views
90

У меня есть поле таблицы membername, которое содержит как фамилию, так и имя пользователя. Можно ли разбить их на 2 поля memberfirst, memberlast?Разделимое значение из одного поля в два

Все записи имеют этот формат «Имя Фамилия» (без кавычек и пробела между ними).

+0

«Все записи имеют этот формат« Имя Фамилия »(без кавычек и пробел между ними)». ... чудом ... Пожалуйста, ** пожалуйста **, не забывайте о таких людях, как я, когда принимаете решения в базе данных. Слишком часто я получаю сайты, рассказывающие мне, что моя фамилия содержит символ * незаконного * (sic) ... :( –

+0

@StijndeWitt. Вы правы в целом, однако кажется, что эта база данных не содержит вашего имени, по крайней мере, не в его официальная форма. В моей стране сначала написаны фамилии, поэтому я также должен быть «дискриминирован» в этой таблице данных. Посмотрите это -> –

ответ

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

+0

Отличное решение этой проблемы! – Bergkamp

+0

Вы все еще не можете использовать IN как «массив значений» из этой операции разделения? – Miguel

4

Единственный случай, когда вы можете такую ​​функцию это запрос UPDATE, который изменит вашу таблицу, чтобы сохранить имя и фамилию в отдельных полях.

Разработка баз данных должны следовать определенным правилам, и 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

+0

Это будет захватывать первую и последнюю помеченные пробелом подстроку из поля, которая не работает при любых обстоятельствах. Например, если поле имени «Lilly von Schtupp», то вы получите «Lilly», «Schtupp» в качестве имени, фамилии. –

19

Если ваш план должен сделать это в рамках запроса, пожалуйста DON» t сделать это (a). Серьезно, это убийца производительности. Могут быть ситуации, когда вы не заботитесь о производительности (например, одноразовые задания на миграцию для разделения полей, позволяющие повысить производительность в будущем), но если вы делаете это регулярно для чего-либо другого, кроме базы данных mickey-mouse, вы можете «тратить ресурсы.

Если у вас есть , вам нужно обработать только часть столбца в некотором роде, ваш дизайн БД неисправен. Он может хорошо работать в домашней адресной книге или рецепте приложения или любой из множества других небольших баз данных, но он не будет масштабироваться для «реальных» систем.

Сохраните компоненты имени в отдельных столбцах. Почти всегда гораздо быстрее присоединяться к столбцам вместе с простой конкатенацией (когда вам нужно полное имя), чем разделять их друг на друга с поиском символов.

Если по какой-то причине вы не можете разделить это поле, по крайней мере, добавить дополнительные столбцы и использовать триггер insert/update для их заполнения. Хотя это не 3NF, это гарантирует, что данные все еще согласованы и будут значительно ускорять ваши запросы. Вы также можете обеспечить, чтобы дополнительные столбцы были обнулены (и индексировались, если вы их просматриваете) одновременно, чтобы не приходилось сталкиваться с проблемами дел.

И если вы даже не можете добавлять столбцы и триггеры, имейте в виду (и сообщите клиенту, если это для клиента), что он не масштабируется.


(а) Конечно, если ваше намерение состоит в том, чтобы использовать этот запрос исправить схиму, так что имена помещаются в отдельные столбцы в таблице, а не запроса, Я считаю, что это допустимое использование. Но я повторяю, что делать это в запросе - это не очень хорошая идея.

+4

Иногда вы должны это делать. F.E. Мне нужно это в сценарии миграции, поэтому мне не нужны спектакли. –

+1

Вы даже прочитали вопрос? – dfmiller

+0

@dfmiller, да, я сделал, следовательно, мой аргументированный и подробный ответ, и спасибо за ваш интерес. Если у вас есть проблема с конкретным вопросом с чем-то, что я написал, укажите это, и я увижу, можно ли его улучшить. Ваш текущий комментарий в значительной степени бесполезен в улучшении ситуации, если это действительно ваше намерение. Или, может быть, вы просто нападаете на случайные комментарии в сети, трудно сказать :-) Я согласен с ответом, конечно, доступ к подколоночному доступу не является масштабируемым и почти всегда плохая идея, если только он не используется для целей фактически _fixing_ sub-columnar доступ. – paxdiablo

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 и устанавливает константу в NULL.
  • имя_источника значения, которые имеют несколько пробелов: он добавит все до первого места в memberfirst и остаток (включая дополнительные пробелы) в член.

версия 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 
    ); 
+0

ничего себе! отлично. Благодарю. – Pons

+0

хороший. решил мою проблему. – Aris

+0

изумительный !! thankyou –

-3

MySQL 5.4 обеспечивает нативную сплит функции:

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

Можете ли вы предоставить ссылку на документацию. Поиск dev.mysql.com выглядит сухим. В разделе 12.5 есть предложения сообщества в комментариях к этой функции. – DRaehal

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 с фамилией, одним словом, первым именем все до этого единственного слова, где имя может быть нулевым, 1 слово, 2 слова или более 2 слов. Т.е.: Null; Мэри; Мэри Смит; Мэри А. Смит; Мэри Сью Эллен Смит;

Так что, если имя является одним словом или null, last_name равно null. Если имя> 1 слово, last_name - последнее слово, а first_name - все слова перед последним словом.

Обратите внимание, что я уже обрезал вещи, такие как Джо Смит-младший; Джо Смит Эскр. и так далее, вручную, что было болезненно, конечно, но это было достаточно мало, чтобы сделать это, поэтому вы хотите убедиться, что действительно посмотрите данные в поле имени, прежде чем принимать решение о том, какой метод использовать.

Обратите внимание, что это также обрезает результат, поэтому вы не получите пробелов перед именами или после них.

Я просто размещаю это для других, которые могли бы по-своему искать здесь то, что мне нужно. Это работает, конечно, сначала проверяет его.

Это одноразовая вещь, поэтому я не забочусь об эффективности.

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 и last_name, когда все данные были получены в поле first_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` 
; 

Я думаю, что не нужно иметь дело с более, чем из двух слов имен в данной конкретной ситуации. Если вы хотите, чтобы сделать это правильно, расщепление может быть очень трудно или даже невозможно в некоторых случаях:

  • Эдгар Аллан Poe
  • Иоганн Вольфганг фон Гете
  • Якоб Людвиг Феликс Мендельсон-Бартольди
  • Lea Мендельсон Бартольди
  • Пе TOFI Шандор
  • 黒 澤

В правильно спроектированной базе данных, человеческие имена должны быть сохранены как в частях и в целом. Конечно, это не всегда возможно.

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 
    ); 
Смежные вопросы