У меня есть поле таблицы membername
, которое содержит как фамилию, так и имя пользователя. Можно ли разбить их на 2 поля memberfirst
, memberlast
?
Все записи имеют этот формат "Имя Фамилия" (без кавычек и пробела между ними).
У меня есть поле таблицы membername
, которое содержит как фамилию, так и имя пользователя. Можно ли разбить их на 2 поля memberfirst
, memberlast
?
Все записи имеют этот формат "Имя Фамилия" (без кавычек и пробела между ними).
К сожалению, в 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;
Вариант 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';
Этот подход также предусматривает:
Версия 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
);
Если ваш план должен сделать это как часть запроса, не делайте этого (a). Серьезно, это убийца производительности. Могут быть ситуации, когда вы не заботитесь о производительности (например, одноразовые задания на миграцию для разделения полей, позволяющие повысить производительность в будущем), но если вы делаете это регулярно для чего-либо другого, кроме базы данных mickey-mouse, вы можете "тратить ресурсы".
Если вам когда-либо приходилось обрабатывать только часть столбца каким-то образом, ваш дизайн БД имеет недостатки. Он может хорошо работать в домашней адресной книге или рецептурном приложении или в любой из множества других небольших баз данных, но он не будет масштабироваться для "реальных" систем.
Сохраните компоненты имени в отдельных столбцах. Это почти всегда намного быстрее, чтобы присоединиться к столбцам вместе с простой конкатенацией (когда вам нужно полное имя), чем разделить их на части с поиском символов.
Если по какой-то причине вы не можете разделить поле, по крайней мере, добавить дополнительные столбцы и использовать триггер insert/update для их заполнения. Хотя это не 3NF, это гарантирует, что данные все еще согласованы и будут значительно ускорять ваши запросы. Вы также можете обеспечить, чтобы дополнительные столбцы были обнулены (и индексировались, если вы их просматриваете), в то же время, чтобы не возникало проблем с ситуациями.
И если вы даже не можете добавлять столбцы и триггеры, имейте в виду (и сообщите клиенту, если это для клиента), что он не масштабируется.
(a) Конечно, если вы намерены использовать этот запрос для исправления схемы, чтобы имена помещались в отдельные столбцы в таблице, а не в запрос, я бы подумал, что чтобы быть действительным использованием. Но я повторяю, делать это в запросе не очень хорошая идея.
Кажется, что существующие ответы слишком сложны или не являются строгим ответом на конкретный вопрос.
Я думаю, что простой ответ - следующий запрос:
SELECT
SUBSTRING_INDEX('membername', ' ', 1) AS 'memberfirst',
SUBSTRING_INDEX('membername', ' ', -1) AS 'memberlast'
;
Я думаю, что в этой конкретной ситуации нет необходимости иметь дело с именами, превышающими два слова. Если вы хотите сделать это правильно, в некоторых случаях разделение может быть очень трудным или даже невозможным:
В правильно спроектированной базе данных имена людей должны храниться как по частям, так и целиком. Это не всегда возможно, конечно.
используйте этот
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX( `membername` , ' ', 2 ),' ',1) AS b,
SUBSTRING_INDEX(SUBSTRING_INDEX( `membername` , ' ', -1 ),' ',2) AS c FROM `users` WHERE `userid`='1'
Не совсем отвечая на вопрос, но столкнувшись с той же проблемой, я закончил это:
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
В MySQL это работает:
SELECT Substring(nameandsurname, 1, Locate(' ', nameandsurname) - 1) AS
firstname,
Substring(nameandsurname, Locate(' ', nameandsurname) + 1) AS lastname
FROM emp
Единственный случай, когда вы можете использовать такую функцию, - это запрос UPDATE, который изменит вашу таблицу, чтобы сохранить имя и фамилию в отдельных полях.
Конструкция базы данных должна соответствовать определенным правилам, а Нормализация базы данных является одним из наиболее важных
У меня была колонка, где первое и последнее имя были оба в одном столбце. Имя и фамилия были разделены запятой. Приведенный ниже код работал. Нет ошибки проверки/коррекции ошибок. Просто немой раскол. Используется phpMyAdmin для выполнения инструкции SQL.
UPDATE tblAuthorList SET AuthorFirst = SUBSTRING_INDEX(AuthorLast,',',-1) , AuthorLast = SUBSTRING_INDEX(AuthorLast,',',1);
Здесь вы берете 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
)
);
Метод, который я использовал для разбивки 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
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
);
mysql 5.4 предоставляет встроенную функцию разделения:
SPLIT_STR(<column>, '<delimiter>', <index>)