1
votes

Rechercher des valeurs délimitées par des virgules dans la base de données avec la requête SELECT MYSQL

J'ai un problème pour obtenir les résultats de la base de données. J'ai une colonne appelée "Régions" qui contient en tant que valeur toutes les régions que l'utilisateur a choisies via le formulaire d'inscription à la newsletter avec des virgules, c'est-à-dire "Moyen-Orient, Europe"

Je crée un filtre qui devra obtenir la liste de tous les utilisateurs qui inscrivez-vous pour une ou plusieurs régions. Les utilisateurs peuvent sélectionner plusieurs régions. À partir du frontend, j'obtiens toutes les régions sélectionnées dans ce format "Global, Middle East" que je dois utiliser dans ma requête SQL pour trouver tous les utilisateurs qui ont le Global et le Moyen-Orient comme région choisie.

J'ai essayé d'utiliser FIND_IN_SET mais cela n'aide pas vraiment. J'ai essayé ce qui suit

 $trimmedRegions = rtrim($sortType,', ');

 $query = "SELECT * FROM health_alerts_subscribers
            WHERE FIND_IN_SET(Regions, $trimmedRegions)";

Des idées comment je peux obtenir le résultat souhaité s'il vous plaît?


8 commentaires

La meilleure solution serait de refactoriser votre base de données et d'utiliser une table séparée et une table de liens pour stocker ces données. Les colonnes contenant des données textuelles délimitées vous causeront toujours plus de maux de cœur à la fin plutôt que de passer quelques minutes à concevoir correctement la base de données


"une valeur contient toutes les régions que l'utilisateur a choisies via le formulaire d'inscription à la newsletter avec des virgules" - Je suppose que vous regrettez cette décision de conception maintenant. "Les données dépendent de la clé [1NF], de la clé entière [2NF] et rien d'autre que de la clé [3NF] alors aidez-moi Codd ." Curieusement # 1 résultat sur Google pour "la clé toute la clé et rien d'autre que" vous amène sur un autre SO question sur la normalisation des données .


Le FIND_IN_SET devrait fonctionner. Pouvez-vous partager comment il a été utilisé et comment il a fonctionné? J'irais cependant dans la voie normalisée, les données délimitées poseront toujours des problèmes.


@ user3783243 j'ai mis à jour ma question. Vous suggérez donc de garder toutes les régions séparées et d'avoir des valeurs comme oui ou non?


Je pense que si vous voulez toutes les lignes de global, vous pouvez simplement utiliser comme% Global%, vous devrez donc faire une requête par région.


@Vidal et si j'ai plusieurs choix pour le filtre comme Global et Europe?


voyez ma réponse, vous faites 2 comme où région comme ("% Global%") et région comme ("% Europe%")


Vous avez besoin d'un FIND_IN_SET pour chaque valeur individuelle. WHERE FIND_IN_SET (Régions, 'Moyen-Orient') et FIND_IN_SET (Régions, 'Global') . Je ferais un tableau différent qui a une relation avec chaque enregistrement.


4 Réponses :


0
votes

Vous avez à peu près besoin de formater votre SQL comme ceci:

SELECT
    *
FROM
    table
WHERE
    regions = 'Europe' or
    regions like 'Europe,%' or
    regions like '%,Europe' or
    regions like '%,Europe,%' or
    regions = 'Middle East' or
    regions like 'Middle East,%' or
    regions like '%,Middle East' or
    regions like '%,Middle East,%'

En PHP, vous devrez parcourir les régions que l'utilisateur a sélectionnées et créer dynamiquement une requête comme celle-ci. p>


3 commentaires

Pourquoi tant de likes, vous pouvez utiliser un wild et le début et un autre à la fin. comme "% value%"


@Vidal Je n'ai aucune idée de ce à quoi ressemble la liste complète des régions, donc si régions contient quelque chose comme Global, Middle East, Europe, East, Asia puis % East % renverrait trop de résultats.


@Vidal Je suis sûr qu'il est possible de REGEXP_LIKE () toute cette situation, mais je n'ai pas la patience de comprendre pour OP. Ils devraient normaliser leurs tables et poursuivre leur vie. Ce sera un vrai sh * t-show si une région change de nom, de capitalisation ou se divise en plusieurs régions ou quelque chose du genre.



0
votes

Je peux suggérer cette approche.

SELECT * FROM table
WHERE 
   region like("%Global%")
   and region like ("%Middle East%")

De cette façon, vous pouvez faire en sorte que les gens s'abonnent aux deux. Vous pouvez l'adapter à vos besoins, ce ne sera évidemment pas la meilleure solution, mais vous pouvez l'utiliser pour créer un tableau croisé dynamique au cas où vous voudriez mettre à jour votre structure de base de données.


11 commentaires

mais comme ceux-ci, j'aurai beaucoup de demandes et je dois sélectionner les résultats choisis et non statiques


Vous souhaitez obtenir la liste d'abonnement pour envoyer un e-mail? quel est le but de voir si je peux vous obtenir une meilleure réponse?


Oui, je devrai obtenir la liste qui sera ensuite importée dans la liste de diffusion par les régions.


ok, vous pouvez faire la requête [SELECT * FROM table WHERE region like ("% Global%")] et obtenir tous les abonnés globaux, puis les enregistrer dans la liste de diffusion globale, puis effectuer une requête pour la région suivante Moyen-Orient et fils sur.


ok mais que dois-je faire avec les utilisateurs qui ont plusieurs régions comme valeur? Avec une seule requête, cela n'apporte pas que les utilisateurs


Je pense que ce n'est pas une requête ponctuelle, vous devrez peut-être interroger toutes les différentes régions individuellement. Les utilisateurs qui sont abonnés à plusieurs régions, ils seront dans leur liste de diffusion correspondante peuvent être multiples comme ils l'ont sélectionné.


Donc, si j'ai toutes les régions dans des colonnes séparées avec une valeur "oui" ou "non", est-ce que j'obtiendrai le résultat? L'utilisateur doit recevoir un e-mail avec toutes les régions et non plusieurs e-mails


OK maintenant je suis confus, si vous allez envoyer à l'utilisateur ses régions, interrogez simplement la table sans filtre où ni région. Que voulez-vous obtenir de la table? Quel est le but si vous pouvez partager cela?


J'ai besoin d'envoyer par e-mail les nouvelles de l'utilisateur sur ses régions sélectionnées, donc j'ai besoin de savoir quels utilisateurs sont par exemple pour l'Europe et l'Asie, donc j'exporte cette liste


Vous envoyez un e-mail différent pour chaque région?


OK alors mon 4ème commentaire est ce dont vous avez besoin., Vous devrez faire une requête par région.



1
votes

Je recommande ce que dit user3783243. J'irais avec FIND_IN_SET. Voici un exemple.

SELECT {colonnes} FROM {table} WHERE FIND_IN_SET ({item_to_search}, {colonne délimitée par des virgules})

Une meilleure façon serait de créez une table régions et ajoutez vos régions, puis créez une table associée appelée, regionsRelated (exemple), puis ajoutez un identifiant de région et de la table de liaison (comme plusieurs à plusieurs)

Table structure example

Table region
id,region
1, Middle East
2, Global

Table user
id,name
1, John
2, Jan

Table userRegion
userId,regionId
1,1
2,1

SELECT user.id,user.name,region.region from user
left join userRegion ON region.userId=user.id
left  join region
where region.region in('Middle East','Global');

Dans votre liste déroulante, sélectionnez simplement toutes les régions et lorsque l'utilisateur sélectionne celles qu'il souhaite, vous les stockez dans le tableau userRegion avec INSERT INTO userRegion (userid, regionId) (1,2); et ainsi de suite.


11 commentaires

à la place item_to_search que dois-je mettre? la chaîne avec des régions délimitées par des virgules sélectionnées? et {colonne délimitée par des virgules} je mets le nom de la colonne?


Alors, recommandez-vous ou pas?


Si je n'ai que chaque région dans une colonne séparée et avec une valeur "oui" ou "non", cela résoudra-t-il mon problème?


Anahit, alors vous devriez continuer à ajouter une nouvelle colonne pour chaque nouvelle région. Ce n'est pas la bonne manière. Je recommande mon exemple ci-dessus.


Si un utilisateur vous écrit un e-mail et dit que sa région n'est pas répertoriée. Ensuite, tout ce que vous avez à faire est d'ajouter la nouvelle région à la table des régions et tout le reste continuera à fonctionner. Vous n'aurez pas à modifier la structure de votre base de données.


Le fait est que les régions sont fixes, ce sont 6 Global, Afrique, Moyen-Orient, Amériques, Asie et Europe


Vous allez aussi sur cette voie. Il y en a techniquement 8. Je créerais une colonne booléenne pour chacun et 1 pour yes / true et 0 pour no / false


Ok et puis avec cela ma requête sera comme sélectionnez où la valeur est 1?


SELECT {colonnes} à partir de {table} WHERE africa = 1 OU asia = 1 et ainsi de suite ... Vous devrez créer la requête en fonction de la sélection de l'utilisateur


Si cela fonctionne, veuillez accepter la réponse. Merci et bonne chance.


A travaillé :) Merci beaucoup



0
votes

Il n'y a pas de fonction exacte pour vos besoins, mais vous pouvez utiliser le code ci-dessous:

$trimmedRegions = rtrim($sortType,', ');
$trimmedRegionsCollection = explode(",", $trimmedRegions);
$trimmedRegionsRegex = implode("|", $trimmedRegionsCollection); // make string like Global|Middle East

$query = 'SELECT * from health_alerts_subscribers WHERE CONCAT(",", `Regions`, ",") REGEXP ",('.$trimmedRegionsRegex.'),"';

J'espère que cela vous aidera.


0 commentaires