BDD : duplication d'enregistrement(s) dans une table
Résolu/Ferméemrh Messages postés 427 Date d'inscription mardi 9 décembre 2014 Statut Membre Dernière intervention 9 avril 2024 - 16 juil. 2022 à 09:05
- BDD : duplication d'enregistrement(s) dans une table
- Probleme de structure de bdd - Forum Programmation
- Problème de remplissage de la BDD - Forum PHP
- Connection à ma bdd free ✓ - Forum Webmastering
- Enregistrer IP dans la bdd ✓ - Forum PHP
- BDD gestion de la paie - Forum compta / gestion
6 réponses
16 juil. 2022 à 09:05
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 !
Modifié le 15 juil. 2022 à 14:16
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.
Modifié le 15 juil. 2022 à 14:39
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
15 juil. 2022 à 14:53
Je pense que mon execute n'est pas bon, il ne reprend pas tous les champs de la table composition présents dans le prepare... Mais c'est là que je ne sais pas faire, je ne veux pas d'un INSERT traditionnel, je voudrais une copie des données de 'contrat' => $value
15 juil. 2022 à 18:42
Bonjour
Dans ron execute tu transmets deux variables.. alors que ta requête SQL n'en n' attend qu'une..
Modifié le 15 juil. 2022 à 18:52
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(); }
15 juil. 2022 à 18:57
Quel couillon, j'ai écrit ligne 64 :
'quantites' => $data_composition['prix'] au lieu de
'quantites' => $data_composition['quantité']
15 juil. 2022 à 18:58
Quelle nouille, j'ai écrit
'quantites' => $data_composition['prix'] au lieu de
'quantites' => $data_composition['quantites']
Modifié le 15 juil. 2022 à 16:06
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 questionModifié le 15 juil. 2022 à 17:01
La 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
15 juil. 2022 à 16:59
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
15 juil. 2022 à 17:31
J'oubliais un truc important : il faut obligatoirement que le traitement soit dans une boucle car un contrat peut avoir plusieurs prestations (plusieurs lignes dans compositions)

Modifié le 15 juil. 2022 à 17:11
Les contrats rattachés au centralisateur :

Le centralisateur dans la table contrats :

15 juil. 2022 à 17:13
Le petit bonhomme vert c'est pour signaler un centralisateur, l'erreur dans la colonne TOTAL c'est parce que la requête 4 déconne !
15 juil. 2022 à 18:09
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.
15 juil. 2022 à 18:35
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 !
15 juil. 2022 à 19:08
Mais en passant par le centralisateyr, tu ne peux pas trouver les lignes de ses contrat puisque le N0 de contrat est le meme sur 2 enregistrements de composition.
15 juil. 2022 à 19:21
J'y arrive avec mon code posté en #14 (correction en #16) mais j'ai dû mal construire ma boucle, je me retrouve avec le contrat du centralisateur composé de 4 x les éléments du clients pris en exemple..