BDD : duplication d'enregistrement(s) dans une table
Résoluemrh Messages postés 427 Date d'inscription Statut Membre Dernière intervention -
Bonjour à tous,
J'aimerai ajouter dans ma table 'compositions' un enregistrement qui serait en partie la recopie d'un autre.
En effet, un ou plusieurs contrats individuels (présents dans la table contrats) seraient neutralisés (passage d'un état 1 à 2) pour être ensuite centralisés, tout en conservant le détail initial (présents dans la table compositions) sur le compte d'un client centralisateur.
Voici mon code (dont la requête 4 de recopie ne fonctionne pas, les autres sont bonnes) que je poste en forum PHP plutôt qu'en forum BDD car j'aimerai que quelqu'un me dise aussi ce qu'il pense des mes boucles dans d'autres boucles !
if (isset($_POST['coche']) AND isset($_POST['client'])) { // Connexion à la base de données : require ("connexion.php"); // Recherche du dernier n° de facture dans la table "contrats" : // (si aucune facture n'est en bdd, on créé la facture n° 500) $requete1 = $bdd->query('SELECT IFNULL(MAX(contrats.facture),499) AS facture FROM contrats'); $data = $requete1->fetch(); $numero = $data['facture'] + 1; // On récupère le client centralisateur : $centralisateur = $_POST['client']; // Récupération de la date du jour : $aujourdhui = date('Y/m/d'); // On créé une entête pour le client centralisateur : $requete2 = $bdd->prepare('INSERT INTO contrats(date_contrat, etat, facture, date_facture, id_client, id_batiment, date_debut, heure_debut, date_fin, heure_fin, adultes, enfants, bebes, animaux) VALUES(:date_contrat, :etat, :facture, :date_facture, :id_client, :id_batiment, :date_debut, :heure_debut, :date_fin, :heure_fin, :adultes, :enfants, :bebes, :animaux)'); $requete2->execute(array( 'date_contrat' =>$aujourdhui, 'etat' =>3, 'facture' =>$numero, 'date_facture' =>$aujourdhui, 'id_client' =>$centralisateur, 'id_batiment' =>5, 'date_debut' =>NULL, 'heure_debut' =>NULL, 'date_fin' =>NULL, 'heure_fin' =>NULL, 'adultes' =>0, 'enfants' =>0, 'bebes' =>0, 'animaux' =>0 )); // Récupération du dernier ID inséré dans la table contrats : $last_insert_id = $bdd->lastInsertId(); // On récupère les numéros de contrats individuels choisis pour être facturés centralisés // Et on remplace leur état 1 par 2 : foreach ($_POST['coche'] as $value): if (!empty($value)): $requete3 = $bdd->prepare('UPDATE contrats SET etat = 2 WHERE id_contrat = :contrat'); $requete3->execute(array('contrat' => $value)); // On recopie les contenus des contrats des clients individuels sur le client centralisateur : $requete4 = $bdd->prepare(' INSERT INTO compositions (id_contrat, id_prestation, descriptif, prix, quantites) SELECT id_contrat, id_prestation, descriptif, prix, quantites FROM compositions WHERE id_contrat = :contrat'); $requete4->execute(array( 'id_contrat' => $last_insert_id, 'contrat' => $value)); endif; endforeach; // Clôture des requètes : $requete1->closeCursor(); $requete2->closeCursor(); $requete3->closeCursor(); $requete4->closeCursor(); }
Je vous remercie d'avance pour votre aide sur ma requête 4 et sur vos conseils quant à la structure de mon code !
- BDD : duplication d'enregistrement(s) dans une table
- Caractére spéciaux dans BDD ✓ - Forum Créer un site
- Impossible d’ouvrir BDD mdb - Forum Access
- Connection à ma bdd free ✓ - Forum Webmastering
- Connexion BDD OVH PHPmyadmin - Forum MySQL
- BDD Gestion Parc Automobile - Forum Access
6 réponses
Après une bonne nuit de sommeil, quelques lignes de codes et boucles en plus, voici mon code qui fonctionne :
if (isset($_POST['coche']) AND isset($_POST['client'])) { // Connexion à la base de données : require ("connexion.php"); // Recherche du dernier n° de facture dans la table "contrats" : // (si aucune facture n'est en bdd, on créé la facture n° 500) $requete1 = $bdd->query('SELECT IFNULL(MAX(contrats.facture),499) AS facture FROM contrats'); $data = $requete1->fetch(); $numero = $data['facture'] + 1; // On récupère le client centralisateur : $centralisateur = $_POST['client']; // Récupération de la date du jour : $aujourdhui = date('Y/m/d'); // On créé une entête pour le client centralisateur : $requete2 = $bdd->prepare('INSERT INTO contrats(date_contrat, etat, facture, date_facture, id_client, id_batiment, date_debut, heure_debut, date_fin, heure_fin, adultes, enfants, bebes, animaux) VALUES(:date_contrat, :etat, :facture, :date_facture, :id_client, :id_batiment, :date_debut, :heure_debut, :date_fin, :heure_fin, :adultes, :enfants, :bebes, :animaux)'); $requete2->execute(array( 'date_contrat' =>$aujourdhui, 'etat' =>3, 'facture' =>$numero, 'date_facture' =>$aujourdhui, 'id_client' =>$centralisateur, 'id_batiment' =>5, 'date_debut' =>$aujourdhui, 'heure_debut' =>NULL, 'date_fin' =>$aujourdhui, 'heure_fin' =>NULL, 'adultes' =>0, 'enfants' =>0, 'bebes' =>0, 'animaux' =>0 )); // Récupération du dernier ID que l'on vient d'insérer dans la table contrats : $last_insert_id = $bdd->lastInsertId(); // Récupération des numéros de contrats à centraliser pour être facturés // Et on remplace leur état 1 validé par 2 centralisé : foreach ($_POST['coche'] as $value): if (!empty($value)): $requete3 = $bdd->prepare('UPDATE contrats SET etat = 2 WHERE id_contrat = :contrat'); $requete3->execute(array('contrat' => $value)); endif; endforeach; foreach ($_POST['coche'] as $value): // Récupération des contenus des contrats individuels cochés : $requete4 = $bdd->prepare(' SELECT * FROM compositions WHERE compositions.id_contrat = :contrat ORDER BY compositions.id_composition ASC'); $requete4->execute(array('contrat' => $value)); // Insertion dans la bdd des compositions en recopie des contrats cochés : while ($data_composition = $requete4->fetch()) { $requete5 = $bdd->prepare('INSERT INTO compositions(id_contrat, id_prestation, descriptif, prix, quantites) VALUES(:id_contrat, :id_prestation, :descriptif, :prix, :quantites)'); $requete5->execute(array( 'id_contrat' => $last_insert_id, 'id_prestation' => $data_composition['id_prestation'], 'descriptif' => $data_composition['descriptif'], 'prix' => $data_composition['prix'], 'quantites' => $data_composition['quantites'] )); } endforeach; // Clôture des requètes : $requete1->closeCursor(); $requete2->closeCursor(); $requete3->closeCursor(); $requete4->closeCursor(); $requete5->closeCursor(); // Envoi à la page contrats : header('Location: contrats.php');
Merci à vous deux pour vous être penché sur mon problème et pour avoir pris le temps de me lire !
Bonjour,
Quel est le message d'erreur ? Si tu n'en as pas c'est peut être que tu ne les gères pas dans ton source, c'est toujours une mauvaise idée de faire l'impasse sur cela.
Après si on regarde le sql
INSERT INTO compositions (id_contrat, id_prestation, descriptif, prix, quantites) SELECT id_contrat, id_prestation, descriptif, prix, quantites FROM compositions WHERE id_contrat = :contrat');
si id_contrat et/ou id_prestation sont des clés primaires de la table tu vas avoir une error duplicate, doublon.
Bonjour JeePee,
Oui tu as raison, j'ai oublié un copié/collé :
Fatal error: Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in /var/www/html/gite/gestion/facturation.php:83 Stack trace: #0 /var/www/html/gite/gestion/facturation.php(83): PDOStatement->execute() #1 {main} thrown in /var/www/html/gite/gestion/facturation.php on line 83
Par ailleurs, dans la table composition, id_contrat et id_prestation sont des clés étrangères... composition a sa propre id_composition, d'ailleurs, elle n’apparaît pas dans mon INSERT INTO
Je viens d'écrire ça qui fonctionne pour l'entete et qui malheureusement vient de m'insérer plus de 1000 lignes dans compositions... J'ai du merdouiller dans les boucles !
if (isset($_POST['coche']) AND isset($_POST['client'])) { // Connexion à la base de données : require ("connexion.php"); // Recherche du dernier n° de facture dans la table "contrats" : // (si aucune facture n'est en bdd, on créé la facture n° 500) $requete1 = $bdd->query('SELECT IFNULL(MAX(contrats.facture),499) AS facture FROM contrats'); $data = $requete1->fetch(); $numero = $data['facture'] + 1; // On récupère le client centralisateur : $centralisateur = $_POST['client']; // Récupération de la date du jour : $aujourdhui = date('Y/m/d'); // On créé une entête pour le client centralisateur : $requete2 = $bdd->prepare('INSERT INTO contrats(date_contrat, etat, facture, date_facture, id_client, id_batiment, date_debut, heure_debut, date_fin, heure_fin, adultes, enfants, bebes, animaux) VALUES(:date_contrat, :etat, :facture, :date_facture, :id_client, :id_batiment, :date_debut, :heure_debut, :date_fin, :heure_fin, :adultes, :enfants, :bebes, :animaux)'); $requete2->execute(array( 'date_contrat' =>$aujourdhui, 'etat' =>3, 'facture' =>$numero, 'date_facture' =>$aujourdhui, 'id_client' =>$centralisateur, 'id_batiment' =>5, 'date_debut' =>NULL, 'heure_debut' =>NULL, 'date_fin' =>NULL, 'heure_fin' =>NULL, 'adultes' =>0, 'enfants' =>0, 'bebes' =>0, 'animaux' =>0 )); // Récupération du dernier ID inséré dans la table contrats : $last_insert_id = $bdd->lastInsertId(); // On récupère les numéros de contrats choisis pour être facturés // Et on remplace leur état 1 par 2 : foreach ($_POST['coche'] as $value): if (!empty($value)): $requete3 = $bdd->prepare('UPDATE contrats SET etat = 2 WHERE id_contrat = :contrat'); $requete3->execute(array('contrat' => $value)); endif; endforeach; // On recopie les contenus des contrats des clients individuels sur le client centralisateur : $requete4 = $bdd->prepare(' SELECT * FROM compositions WHERE compositions.id_contrat = :contrat ORDER BY compositions.id_composition ASC'); $requete4->execute(array('contrat' => $value)); while ($data_composition = $requete4->fetch()) { $requete5 = $bdd->prepare('INSERT INTO compositions(id_contrat, id_prestation, descriptif, prix, quantites) VALUES(:id_contrat, :id_prestation, :descriptif, :prix, :quantites)'); $requete5->execute(array( 'id_contrat' => $last_insert_id, 'id_prestation' => $data_composition['id_prestation'], 'descriptif' => $data_composition['descriptif'], 'prix' => $data_composition['prix'], 'quantites' => $data_composition['prix'] )); } // Clôture des requètes : $requete1->closeCursor(); $requete2->closeCursor(); $requete3->closeCursor(); $requete4->closeCursor(); $requete5->closeCursor(); }
La ligne 83 dans le source original, c'est bien la requete 4 ?
Id_composition est bien en auto_increment ?
L'erreur indique qu'il n'y a pas le bon nombre de valeurs. Tu devrait tester le sql pur dans la console mysql en mettant un n° de contrat à la place de la variable.
Si tu veux initialiser plus de champs, il faut les mettre dans la liste et dans le select. Mais en dupliquant tout, comment vas tu rattacher à un client centralisateur. C'est lors de l'insert qu'il faudrait le faire, après tu aura des lignes dupliquées.
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre questionLa ligne 83 correspond bien à 'contrat' => $value)); // La fin de l'execute de ma requête 4... Les données transmises (id_contrat + contrat qui répond à WHERE id_contrat = :contrat) ne sont pas suffisantes...
L'id_composition actuel est 895, il est bien en auto increment
Les clients ne sont pas rattachés à un centralisateur, ce sont les contrats dont l'entête (table contrats) et la composition (table compositions) qui sont dupliqués et sur lesquel j'impose l'id_client du centralisateur... Je souhaite conserver la consultation des contrats des clients avant centralisation mais avec impossibilité de les modifier (etat :1 => etat :2)
En fait, je suis venu chercher ici de l'aide pour la syntaxe qui me permettrait de recopier des données se trouvant dans la table dans laquelle je veux justement insérer des données sans passer par des affectations de valeurs à des variables...
J'ai essayé de m'inspirer de ça https://www.developpez.net/forums/d954452/bases-donnees/mysql/debuter/dupliquer-enregistrement/ mais je n'y arrive pas
Les requêtes 1, 2 et 3 fonctionnent parfaitement... Quand je vais dans PhpMyAdmin j'ai bien les contrats centralisés dont l'état est passé de 1 à 2 et dans la table contrats j'ai bien une entête créée à l'id_client du centralisateur.
Il faut maintenant que je finalise la requête 4 en allant chercher dans la table compositions et dans une boucle les id_contrats centralisés, et que je les recopie dans cette même table en leur affectant $last_insert_id comme id_contrat
Pour l'exemple dont tu t'es inspiré, tu n'as pas le soucis indiqué puisque tu as un id auto_increment.
Testes la requête sql directe avec le n° de contrat qu'il y a sur le cas "bonhomme vert".
Mais je ne comprends toujours cas comment dans composition, où tout est identique, tu va distinguer les lignes du client original des lignes du client centralisateur.
Dans compositions, la clé étrangère id_contrat lie l'enregistrement avec l'id_contrat clé primaire de la table contrats qui possède son propre id_client. Le contrat 500 est ainsi lié au client 42 par exemple. Si le client 42 est dépendant d'un centralisateur, il est important que son contrat puisse encore être consultable sur la fiche client. Idem pour le client 54 qui a un contrat 527.
Du coup, le centralisateur 17 des clients 42 et 54 possède son propre contrat 685, avec son propre id_contrat 685 et sa composition est la recopie des contrats 500 et 527.
C'est important de conserver les id_contrats 500 et 527 pour pouvoir les consulter dans les fiches des clients 42 et 54, mais il faut aussi consulter et imprimer la facture du contrat 685 sur la fiche du client 17 !