web-dev-qa-db-fra.com

Fractionner la valeur d'un champ à deux

J'ai un champ de table membername qui contient à la fois le nom de famille et le prénom des utilisateurs. Est-il possible de scinder ces champs en 2 champs memberfirst, memberlast

Tous les enregistrements ont ce format "Prénom Nom" (sans les guillemets et un espace entre les deux).

107
tsiger

Malheureusement, MySQL ne propose pas de fonction de division de chaîne. Cependant, vous pouvez créer une fonction définie par l'utilisateur pour cela, telle que celle décrite dans l'article suivant:

Avec cette fonction: 

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 ;

vous seriez capable de construire votre requête comme suit:

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

Si vous préférez ne pas utiliser une fonction définie par l'utilisateur et que la requête soit un peu plus détaillée, vous pouvez également procéder comme suit:

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

SÉLECTIONNER variante (ne pas créer de fonction définie par l'utilisateur):

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

Cette approche prend également en charge:

  • nomutilisateur valeurs sans espace : il ajoutera la chaîne entière à memberfirst et définira memberlast sur NULL.
  • nom_membre les valeurs qui ont plusieurs espaces : il ajoutera tout avant le premier espace à memberfirst et le reste (espaces compris) à memberlast.

La version UPDATE serait:

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

Si votre plan est de faire cela dans le cadre d'une requête, veuillez ne pas le faire (une). Sérieusement, c'est un tueur de performance. Il peut y avoir des situations dans lesquelles vous ne vous souciez pas des performances (telles que des tâches de migration uniques pour scinder les champs permettant d’améliorer les performances à l’avenir), mais si vous le faites régulièrement pour autre chose gaspillez des ressources.

Si vous vous retrouvez jamais dans l'obligation de traiter une partie d'une colonne, votre conception de base de données est défectueuse. Cela fonctionnera peut-être bien avec un carnet d'adresses personnel, une application de recettes ou n'importe laquelle des myriades d'autres petites bases de données, mais cela ne sera pas évolutif pour de "vrais" systèmes.

Stockez les composants du nom dans des colonnes séparées. Il est presque toujours plus rapide de joindre des colonnes avec une simple concaténation (lorsque vous avez besoin du nom complet) que de les séparer avec une recherche de caractères.

Si, pour une raison quelconque, vous ne pouvez pas scinder le champ, insérez au moins les colonnes supplémentaires et utilisez un déclencheur d'insertion/de mise à jour pour les renseigner. Bien que ce ne soit pas 3NF, cela garantira la cohérence des données et accélérera massivement vos requêtes. Vous pouvez également vous assurer que les colonnes supplémentaires sont placées dans la casse inférieure (et indexées si vous les recherchez) en même temps, afin de ne pas avoir à vous occuper de problèmes de casse.

Et, si vous ne pouvez même pas ajouter les colonnes et les déclencheurs, soyez conscient (et informez votre client, s'il s'agit d'un client) qu'il n'est pas évolutif.


(une) Bien sûr, si votre intention est d'utiliser cette requête pour corriger le schéma de sorte que les noms soient placés dans des colonnes séparées dans la table plutôt que dans la requête ,, je considérerais que être une utilisation valide. Mais je le répète, le faire dans la requête n'est pas vraiment une bonne idée.

20
paxdiablo

Il semble que les réponses existantes sont trop compliquées ou ne constituent pas une réponse stricte à une question donnée.

Je pense que la réponse simple est la requête suivante:

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

Je pense qu'il n'est pas nécessaire de traiter avec des noms de plus de deux mots dans cette situation particulière. Si vous voulez le faire correctement, le fractionnement peut être très difficile, voire impossible dans certains cas:

  • Edgar Allan Poe
  • Johann Wolfgang von Goethe
  • Jakob Ludwig Felix Mendelssohn-Bartholdy
  • Lea Mendelssohn Bartholdy
  • Petőfi Sándor
  • 黒 澤

Dans une base de données correctement conçue, les noms humains doivent être stockés à la fois en partie et en totalité. Ce n'est pas toujours possible, bien sûr.

14
Dávid Horváth

utilisez ceci

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

Pas exactement la question, mais devant le même problème, j'ai fini par faire ceci:

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
5
commonpike

Le seul cas où vous souhaiteriez une telle fonction est une requête UPDATE qui modifiera votre table pour stocker Prénom et Nom dans des champs distincts.

La conception de la base de données doit suivre certaines règles, et Normalisation de la base de données est parmi les plus importantes

3
Your Common Sense

Dans MySQL, cela fonctionne avec cette option:

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

J'avais une colonne où le prénom et le nom de famille étaient tous deux dans une colonne. Le prénom et le nom ont été séparés par une virgule. Le code ci-dessous a fonctionné. Il n'y a PAS d'erreur de vérification/correction. Juste une scission muette. Utilisé phpMyAdmin pour exécuter l'instruction SQL.

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

13.2.10 Syntaxe UPDATE

1
Steve R.

Cela prend smhg à partir d’ici et court de Dernier index d’une sous-chaîne donnée dans MySQL et les combine. C’est pour mysql, tout ce dont j'avais besoin était d’obtenir une division correcte du nom en prénom_nom et nom de famille avec le nom de famille un mot unique, le prénom avant tout ce mot unique, où le nom pouvait être null, 1 mot, 2 mots ou plus de 2 mots. Ie: Null; Marie; Mary Smith; Mary A. Smith; Mary Sue Ellen Smith;

Donc, si nom est un mot ou null, nom_nom est null. Si name est> 1 Word, last_name est le dernier Word et first_name tous les mots avant le dernier Word.

Notez que j'ai déjà coupé des choses comme Joe Smith Jr.; Joe Smith Esq. et ainsi de suite, manuellement, ce qui était douloureux, bien sûr, mais suffisamment petit pour le faire. Vous devez donc vous assurer de bien examiner les données dans le champ de nom avant de décider de la méthode à utiliser. 

Notez que cela limite également le résultat, de sorte que vous ne vous retrouvez pas avec des espaces devant ou après les noms.

Je ne fais que poster ceci pour les autres qui pourraient chercher sur Google ce dont j'avais besoin. Cela fonctionne, bien sûr, testez-le d'abord avec select. 

C'est une chose unique, donc je me fiche de l'efficacité.

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

Méthode que j'avais l'habitude de scinder prénom_nom en prénom_nom et nom_dernier lorsque les données sont arrivées dans le champ prénom_nom. Cela ne mettra que le dernier mot dans le champ du nom de famille, ainsi "john phillips sousa" sera le prénom "john phillips" et le nom "sousa". Cela évite également de remplacer tout enregistrement déjà corrigé.

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
0
TheSatinKnight
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
    );
0
Aniket