126 votes

Diviser la valeur d'un champ en deux

J'ai un champ de table membername qui contient à la fois le nom et le prénom des utilisateurs. Est-il possible de les diviser en deux champs memberfirst , memberlast ?

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

7 votes

"Tous les enregistrements ont ce format "Prénom Nom" (sans guillemets et sans espace entre les deux)." ... miraculeusement... S'il vous plaît, s'il vous plaît n'oubliez pas les gens comme moi lorsque vous prenez des décisions concernant les bases de données. Trop souvent, je reçois des sites web qui me disent que mon nom de famille contient un mot de passe. illégal (sic) personnage... :(

0 votes

@StijndeWitt Vous avez raison en général, cependant il semble que cette base de données ne contienne pas votre nom, du moins pas sous sa forme officielle. Dans mon pays, les noms de famille sont écrits en premier, et je serais donc également "discriminé" dans ce tableau de données. Il suffit de voir ceci -->

229voto

Daniel Vassallo Points 142049

Malheureusement, MySQL ne dispose pas d'une fonction de séparation des chaînes de caractères. Cependant, vous pouvez créer un fonction définie par l'utilisateur pour cela, comme celui décrit 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 en mesure 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 vous ne voyez pas d'inconvénient à ce que la requête soit un peu plus verbeuse, 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;

0 votes

Excellente solution pour ce problème !

0 votes

vous ne pouvez toujours pas utiliser le IN comme un "tableau de valeurs" à partir de cette opération de fractionnement ?

3 votes

Est-ce que votre utilisation de LENGTH multibyte sûr ? "LENGTH(str) : Renvoie la longueur de la chaîne de caractères str, mesurée en octets. Un caractère multi-octet compte comme plusieurs octets. Cela signifie que pour une chaîne contenant cinq caractères de 2 octets, LENGTH() renvoie 10, alors que CHAR_LENGTH() renvoie 5."

71voto

smhg Points 702

Variante SELECT (ne pas créer une 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 :

  • nom de membre valeurs sans espace : il ajoutera la chaîne entière à memberfirst et mettra memberlast à NULL.
  • nom de membre les valeurs qui ont plusieurs espaces : il ajoutera tout ce qui précède le premier espace à memberfirst et le reste (y compris les espaces supplémentaires) à 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
    );

0 votes

Il serait également utile de voir comment couper uniquement le dernier mot du nom de famille, et tous les autres mots du prénom, par exemple : Mary A. Smith qui est le type que j'ai à traiter avec cela dans une vieille table db fix. Je vais voir si je peux trouver une solution et poster le résultat, sinon, si vous pouvez poster cette option aussi, votre réponse serait complète.

0 votes

comment pouvons-nous le convertir en entier puisque le nom du membre est un varchar et que le premier membre est de type int. Cela fonctionnera-t-il si j'utilise directement cast() ?

0 votes

Vous méritez une médaille, monsieur.

20voto

paxdiablo Points 341644

Si votre plan est de faire cela dans le cadre d'une requête, s'il vous plaît Ne le fais pas. faire cela (a) . Sérieusement, c'est un tueur de performance. Il peut y avoir des situations où vous ne vous souciez pas des performances (comme des travaux de migration ponctuels pour diviser les champs afin d'obtenir de meilleures performances à l'avenir), mais si vous le faites régulièrement pour autre chose qu'une base de données de type "mickey-mouse", vous gaspillez des ressources.

Si vous jamais Si vous devez traiter une partie seulement d'une colonne, c'est que la conception de votre base de données est défectueuse. Elle peut très bien fonctionner sur un carnet d'adresses personnel, une application de recettes ou une myriade d'autres petites bases de données, mais elle ne pourra pas être adaptée aux "vrais" systèmes.

Stockez les composants du nom dans des colonnes séparées. Il est presque toujours beaucoup plus rapide de joindre des colonnes ensemble 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 diviser le champ, mettez au moins les colonnes supplémentaires et utilisez un déclencheur d'insertion/mise à jour pour les remplir. Bien que cela ne soit pas 3NF, cela garantira la cohérence des données et accélérera considérablement vos requêtes. Vous pouvez également vous assurer que les colonnes supplémentaires sont en minuscules (et indexées si vous effectuez des recherches sur celles-ci) afin de ne pas avoir à vous préoccuper des problèmes de casse.

Et, si vous ne pouvez même pas ajouter les colonnes et les déclencheurs, sachez (et faites savoir à votre client, si c'est pour un client) que ce n'est pas évolutif.


(a) Bien sûr, si votre intention est d'utiliser cette requête pour fixer le schéma afin que les noms soient placés dans des colonnes distinctes dans le fichier tableau plutôt que le requête, Je considère que c'est une utilisation valide. Mais je le répète, le faire dans la requête n'est pas vraiment une bonne idée.

4 votes

Parfois, on est obligé de le faire. Par exemple, j'en ai besoin dans une migration script, donc je ne me soucie pas des performances.

0 votes

@dfmiller, oui, je l'ai fait, d'où ma réponse raisonnée et détaillée, et merci pour votre intérêt. Si vous avez un spécifique Si vous avez un problème avec quelque chose que j'ai écrit, signalez-le et je verrai si je peux l'améliorer. Votre commentaire actuel est plutôt inutile pour améliorer la situation, si telle était bien votre intention. Ou peut-être que vous avez juste comme en débitant des commentaires au hasard sur le net, c'est difficile à dire :-) Je maintiens ma réponse, bien sûr, l'accès aux sous-colonnes n'est pas extensible et est presque toujours une mauvaise idée, à moins qu'il ne soit utilisé dans le but d'améliorer la qualité de l'information. fixation de accès aux sous-colonnes.

3 votes

La question est de savoir comment diviser la colonne unique en deux, et vous répondez en disant "Ne faites pas ça", puis vous expliquez pourquoi il faut les diviser. Votre premier paragraphe donne l'impression que vous plaidez en faveur du maintien d'une seule colonne, mais les autres paragraphes disent le contraire.

7voto

Karthik Points 1226

utiliser ce

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 votes

Cette méthode permet de récupérer la première et la dernière sous-chaîne délimitée par des espaces dans le champ, ce qui ne fonctionne pas dans toutes les circonstances. Par exemple, si le champ du nom est "Lilly von Schtupp", vous obtiendrez "Lilly", "Schtupp" comme prénom et nom.

3voto

Le seul cas où vous pouvez avoir besoin d'une telle fonction est une requête UPDATE qui modifie votre table pour stocker le prénom et le nom dans des champs séparés.

La conception des bases de données doit suivre certaines règles, et Normalisation des bases de données est parmi les plus importants

1 votes

Commentaire inutile car c'est exactement ce que le posteur a demandé ; également inexact car il y a un million de fois où vous pouvez avoir besoin de diviser une chaîne pour une meilleure normalisation. Je ne sais pas pourquoi ni comment ce commentaire a été voté.

0 votes

Utiliser des index sur des champs fractionnés est à peu près aussi impossible que de transformer MySQL en broyeur de feuilles, mais cela n'empêchera pas les gens de poser des questions à ce sujet. Bonne réponse : la base de données devrait refléter les données, pas les spécifications de votre broyeur de feuilles.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X