Разделить значение из одного поля в два

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

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

Ответ 1

К сожалению, в MySQL нет функции разделения строк. Однако для этого можно создать пользовательскую функцию, например, описанную в следующей статье:

С помощью этой функции:

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;

Ответ 2

Вариант 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 и установит константу в 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
    );

Ответ 3

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

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

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

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

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


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

Ответ 4

Кажется, что существующие ответы слишком сложны или не являются строгим ответом на конкретный вопрос.

Я думаю, что простой ответ - следующий запрос:

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

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

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

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

Ответ 5

используйте этот

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

Ответ 6

Не совсем отвечая на вопрос, но столкнувшись с той же проблемой, я закончил это:

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

Ответ 7

В MySQL это работает:

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

Ответ 8

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

Конструкция базы данных должна соответствовать определенным правилам, а Нормализация базы данных является одним из наиболее важных

Ответ 9

У меня была колонка, где первое и последнее имя были оба в одном столбце. Имя и фамилия были разделены запятой. Приведенный ниже код работал. Нет ошибки проверки/коррекции ошибок. Просто немой раскол. Используется phpMyAdmin для выполнения инструкции SQL.

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

13.2.10 Синтаксис UPDATE

Ответ 10

Здесь вы берете smhg и сокращаете Последний индекс данной подстроки в MySQL и объединяете их. Это для mysql, все, что мне нужно было, чтобы получить приличный раскол имени для first_name last_name с фамилией, одним словом, первым именем все до этого единственного слова, где имя может быть нулевым, 1 слово, 2 слова или более 2 слов. Т.е.: Null; Мэри; Мэри Смит; Мэри А. Смит; Мэри Сью Эллен Смит;

Итак, если имя - одно слово или null, last_name равно null. Если name > 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
    ) 
);

Ответ 11

Метод, который я использовал для разбивки 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

Ответ 12

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

Ответ 13

mysql 5.4 предоставляет встроенную функцию разделения:

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