PHP PDO : envoyer une requête de mise-à-jour automatique avec GROUP_CONCAT [Résolu]

Signaler
Messages postés
34
Date d'inscription
dimanche 19 juillet 2020
Statut
Membre
Dernière intervention
21 février 2021
-
Messages postés
34
Date d'inscription
dimanche 19 juillet 2020
Statut
Membre
Dernière intervention
21 février 2021
-
Bonjour à tous,
J'ai créé une fonction qui permet d'obtenir les données d'une table (des menus dans l'exemple) et je voudrais lancer une mise-à-jour juste avant d'exécuter la fonction, afin d'obtenir les valeurs actuelles, en évitant de passer par phpMyAdmin pour effectuer la mise-à-jour.
J'ai une requête UPDATE qui fonctionne comme ça:
Il s'agit d'obtenir les libellés des produits de la table produits dont le champ 'menu' est identique (égal à 1, ou 2, ou 3, ou 4 etc.) afin de les concaténer dans le champ 'descriptif_menu' selon le champ 'menu' des lignes de ma table menus.
UPDATE menus SET descriptif_menu = (SELECT GROUP_CONCAT(label SEPARATOR ', ') FROM produits WHERE menu = :menu GROUP BY menu) WHERE menu = :menu;

Et je dois la réitérer pour chaque valeur
:menu
; donc 3 requêtes pour 3 menus ou 5 requêtes pour 5 menus.
Je voudrais automatiser cette requête pour ne pas limiter le nombre de menus possibles.
J'ai donc tenté ça :
require connexion_bdd.inc;
try{
 $menu = 1++;
 $sql_update = "UPDATE menus SET descriptif_menu = (SELECT GROUP_CONCAT(label SEPARATOR ', ') FROM produits WHERE menu = $menu GROUP BY menu) WHERE menu = $menu";
 $requete = $bdd->prepare($sql_update);
 $requete->execute();
} catch (PDOException $e) {
 echo 'Erreur : ',$e->getMessage(),'<br />';
 die();
}

..et ça marche pas !!
J'ai tenté avec
$menu = '1++';
, sans résultat.
J'ai tenté avec
$sql_update = "UPDATE menus SET descriptif_menu = (SELECT GROUP_CONCAT(label SEPARATOR ', ') FROM produits WHERE menu = :menu GROUP BY menu) WHERE menu = :menu";
$requete->bindParam(':menu',$menu);
avec les mêmes essais du
$menu=1++;
et aucun résultat.
Je pense qu'il y a moyen de faire varier ce
$menu
pour qu'il soit opérant entre 1 et N (entier positif) mais je ne trouve pas la bonne syntaxe, si c'est une question de syntaxe...

Est-ce que ça parle à l'un de vous ?
Merci de votre lecture ;p

4 réponses

Messages postés
31458
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
23 février 2021
3 277
Bonjour,

$menu = 1++; ... ça revient à écrire $menu = 2;

Où est initialisée ta variable menu ?
Sachant que pour l'incrémenter.. il suffit de faire $menu++;

Mais si je comprend bien ce que tu veux faire .. c'est une boucle de 1 à N ... ?
Donc.. pour ça..il faut faire une boucle...
for($menu=1; $menu<10; $menu++){
   //ici $menu prendra les valeurs de 1 à 9 

}


Par contre, quel est l'intéret de stocker dans ton champ descriptif_menu la concaténation... que tu peux, de toutes façons, obtenir lorsque tu fais ta requête SELECT pour afficher les infos de tes menus ?
A part dupliquer les données en bdd ( ce qui est source d'erreur).. il n'y a aucune utilité...



Messages postés
34
Date d'inscription
dimanche 19 juillet 2020
Statut
Membre
Dernière intervention
21 février 2021

Bonsoir jordane45,
Merci de ta réponse, le but est la mise-à-jour avant la requête select qui affiche simplement (via une fonction) les lignes de la table menus :
function GetMenus(){
require ('cnxbdd.inc'); //connexion bdd
try{
	$sql = "SELECT * FROM menus ORDER BY menu";
	$datas = $bdd->query($sql);
	foreach ($datas as $row) {
	$label = htmlspecialchars($row['label_menu']);
	$descriptif = htmlspecialchars($row['descriptif_menu']);
	$prix = $row['prix_menu'];
	$str1 = " <h3>";
	$str2 = "</h3>";
	$str3 = "<p>Composé par les plats : ";
	$str4 = ", est au prix de <em>";
	$str5 = " €</em>.</p><br />";
	echo $str1 . $label . $str2 . $str3 . $descriptif . $str4 . $prix . $str5;
	}
} catch (PDOException $e) {
	echo $e->getMessage();
	}
require ('oxied.inc'); //fermeture de la connexion et vidage de la requête
}

Ce qui donne :
<p> </p>
 <h3>Menu de la semaine</h3>
<p>Composé par les plats : Potage de saison, Poulet à la Bière, est au prix de <em>9.90 €</em>.</p>
<br />
 <h3>Menu du samedi</h3>
<p>Composé par les plats : Velouté au Fromage, Canard sauce aux Cèpes, est au prix de <em>11.50 €</em>.</p>
<br />
 <h3>Menu du dimanche</h3>
<p>Composé par les plats : Soupe Galloise (Cawl), Aligot & Saucisse, est au prix de <em>12.50 €</em>.</p>
<br />
<p> </p>

Mais lorsqu'un nouveau produit intègre un menu, ou qu'un nouveau menu est créé, je veux mettre-à- jour le champ "descriptif_menu" qui passe par la requête :
UPDATE menus SET descriptif_menu = (SELECT GROUP_CONCAT(label SEPARATOR ', ') FROM produits WHERE menu = :menu GROUP BY menu) WHERE menu = :menu

avec le code php suivant :
try{
	$sql2 = "UPDATE menus SET descriptif_menu = (SELECT GROUP_CONCAT(label SEPARATOR ', ') FROM produits WHERE menu = 1 GROUP BY menu) WHERE menu = 1";
	$requete2 = $bdd->prepare($sql2);
	$requete2->execute();
	$sql3 = "UPDATE menus SET descriptif_menu = (SELECT GROUP_CONCAT(label SEPARATOR ', ') FROM produits WHERE menu = 2 GROUP BY menu) WHERE menu = 2";
	$requete3 = $bdd->prepare($sql3);
	$requete3->execute();
	$sql4 = "UPDATE menus SET descriptif_menu = (SELECT GROUP_CONCAT(label SEPARATOR ', ') FROM produits WHERE menu = 3 GROUP BY menu) WHERE menu = 3";
	$requete4 = $bdd->prepare($sql4);
	$requete4->execute();
} catch (PDOException $e) {
	echo 'Erreur : ',$e->getMessage(),'<br />';
	die();
}

Car il y a 3 menus différents.
Donc si j'ai un 4ème menu de créé, ou même un cinquième, etc., je veux pouvoir n'envoyer qu'une seule requête, en faisant varier seulement
:menu
ou
$menu
. Et là, je n'arrive pas à trouver la syntaxe.
Messages postés
34
Date d'inscription
dimanche 19 juillet 2020
Statut
Membre
Dernière intervention
21 février 2021

Du coup j'ai modifié mon code avec ton éclairage :
try{
	for($menu=1; $menu<10; $menu++) {
	$sqlu = "UPDATE menus SET descriptif_menu = (SELECT GROUP_CONCAT(label SEPARATOR ', ') FROM produits WHERE menu = $menu GROUP BY menu) WHERE menu = $menu";
	$requete = $bdd->prepare($sqlu);
	$requete->execute(); }
} catch (PDOException $e) {
	echo 'Erreur : ',$e->getMessage(),'<br />';
	die();
}

Et ça fonctionne exactement comme je le voulais !
=)
Merci beaucoup, encore une fois !!!
Messages postés
34
Date d'inscription
dimanche 19 juillet 2020
Statut
Membre
Dernière intervention
21 février 2021

Je comprends bien que je pourrais intégrer le descriptif_menu lors de l'extraction des champs des menus en couplant les deux requêtes SELECT, mais ça ne mettrait pas à jour la table des menus. Or, c'est cette mise-à-jour que je recherche. Sinon, effectivement, je ne vois pas vraiment l'utilité d'une table menus...

En tous cas, je te remercie bien, jordane45, pour ta célérité, ta compréhension et la justesse de tes conseils !
Messages postés
31458
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
23 février 2021
3 277
On a déjà eu cette discussion... et j'insiste ....

Ton schéma de BDD n'est pas bon !

Tu devrais avoir un truc de ce genre


(en ajoutant d'autres champs si besoin.. )

Mais donc
Une table MENUS .. qui ne contient rien de plus que la liste des menus ( que le nom du menu et son prix )
Une table PLATS : qui contient l la liste des différents plats possibles ( dès fois qu'un jour tu fasses (ou ton pote) de la vente "à la carte" )
Une table de liaison qui permet d'assigner à un menu.. des plats.. (un même produit pouvant se trouver dans différents menus )

Ensuite, pour récupérer la liste des plats d'un menu, il suffit d'utiliser les JOINTURES sur les requêtes SQL.

Voila.. c'est un fonctionnement "normal" contrairement à ce que tu fais...
Messages postés
34
Date d'inscription
dimanche 19 juillet 2020
Statut
Membre
Dernière intervention
21 février 2021

J'ai bien compris !
J'ai choisi la solution d'une table menus avec un champ de description, puisque si (effectivement) mon pote est intéressé par faire lui-même un descriptif de son menu (dans le cas ou il trouverait une utilité à créer des menus dans son activité), la fonction
GetMenus()
n'aura pas besoin d'être changée, simplement tronquer le code en "sortant" les requêtes de mise-à-jour (pourquoi pas via la gestion d'un
include
?).
Si je pars de ton merise de la bdd, j'imagine devoir aussi créer plusieurs
include
afin de gérer ces descriptifs, voire c'est impossible en partant de cette architecture ?
Enfin bon !
On en apprends tous les jours n'est-ce pas ?
Je te souhaite une bonne soirée.
Messages postés
31458
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
23 février 2021
3 277
Il suffit de mettre un champ descriptif dans la table Menu que ton pote pourra remplir avec du texte si il le souhaites.

Et si il ne veut plus afficher la liste des produits, là, il suffit en effet de mettre cette partie dans un include et donc de ne plus l'inclure si il ne les veut plus....

Ce qu'il faut, c'est éviter d'avoir des données redondantes dans les tables....
Messages postés
31458
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
23 février 2021
3 277 >
Messages postés
31458
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
23 février 2021

Avec la structure que je t'ai donné :

La requête deviendrait un truc du genre
SELECT M.*
             ,GROUP_CONCAT(P.nom_du_plat SEPARATOR ', ') as LISTE_PLATS
FROM  menus_plats MP
LEFT JOIN menus M ON M.id = MP.id_menu
LEFT JOIN plats P  ON P.id = MP.id_plats
WHERE MP.id_menu = 1
GROUP BY MP.id_menu

A noter que le WHERE n'est pas obligatoire .. il ne sert que si tu veux afficher les infos que d'un seul menu.

Et donc.. en une seule requête.. tu as toutes les infos de ton menu + la liste des plats concaténés ...

Teste cette requête directement en BDD dans phpmyadmin .. tu verras ce que ça donne...
Messages postés
34
Date d'inscription
dimanche 19 juillet 2020
Statut
Membre
Dernière intervention
21 février 2021
>
Messages postés
31458
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
23 février 2021

Bonjour !
J'ai déjà une table menus avec un champ descriptif_menu que je peux modifier directement par phpMyAdmin, et une table produits, dont la primary key (unique) est '
reference' int(5) NOT NULL AUTO_INCREMENT
.
J'ai essayé ça :
CREATE TABLE `menus_produits` (
  `menu` int(5) NOT NULL AUTO_INCREMENT,
  `descriptif_menu` varchar(300) NOT NULL,
  `reference` varchar(300) NOT NULL,
  PRIMARY KEY (`menu`)
) ENGINE=MyISAM AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;

INSERT INTO `menus_produits` VALUES (1,'Menu de fin de semaine',''),(2,'Menu du samedi',''),(3,'Menu du dimanche','');

SELECT menus.* ,GROUP_CONCAT(produits.label SEPARATOR ', ') as labels
FROM menus_produits
LEFT JOIN menus ON menus.menu = menus_produits.menu
LEFT JOIN produits ON produits.reference = menus_produits.reference
WHERE menus_produits.menu = 1
GROUP BY menus_produits.menu;

J'avais essayé en laissant la 'reference' à
int(5)
comme dans la table produits mais il fallait que je rentre l'insert :
INSERT INTO `menus_produits` VALUES (1,'Menu de fin de semaine',NULL),(2,'Menu du samedi',NULL),(3,'Menu du dimanche',NULL)
pour que ça ne fasse pas d'erreur.

J'ai donc ce retour :
+------+------------------------+---------------------------------------+-----------+--------+
| menu | label_menu             | descriptif_menu                       | prix_menu | labels |
+------+------------------------+---------------------------------------+-----------+--------+
|    1 | Menu de fin de semaine | Potage de saison, Poulet à la Bière   |      9.90 | NULL   |
+------+------------------------+---------------------------------------+-----------+--------+
1 row in set (0.001 sec)

J'ai essayé en remplaçant le second LEFT JOIN par RIGHT JOIN mais ça me donne rien de mieux. Une erreur traîne et je ne sais pas où ?
Messages postés
34
Date d'inscription
dimanche 19 juillet 2020
Statut
Membre
Dernière intervention
21 février 2021

Je pense comprendre la limite de mon merise, lorsqu'il s'agit de plusieurs menus qui peuvent contenir des mêmes produits.
En y réfléchissant, j'imagine une chaîne de charactère à la place de l'entier pour chaque plat, décodée par php, plutôt que plusieurs colonnes "menu1", "menu2", "menu3", encore que...
Et il doit bien exister une syntaxe, ou un genre de fonction, sql, qui "fasse le tri" ?...
Du coup, c'est plutôt une méthode d'apprentissage à la "Rousseau" qu'une méthode à la "Voltaire" !
:)