Effectuer un INSERT associé à SELECT et UPDATE + auto_increm

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : Effectuer un INSERT associé à SELECT et UPDATE + auto_increm

par Ajoloca » 24 déc. 2006, 17:53

Re,

Mon idée pour ce champ "date" c'est qu'il fait office de flag - si rempli - mais aussi il te permettra de supprimer tes enregistrements plus vieux de X temps.

par karpediem » 24 déc. 2006, 17:48

Bonjour,

Mais tu ne dors jamais ? tu es là la nuit et le jour :D

ça y est, j'ai eu LA révélation suite à la leture d'une phrase simple "je pense que tu te compliques la vie"...

La date ne peut pas faire partie de ma clé, mais en revanche je peux gérer la totalité de mes enregistrements dans une seule et unique table avec un flag "sauvegarde/non sauvegarde" ! J'étais partie sur 2 tables afin d'optimiser les temps de traitement => des requetes sur des tables moins grosses et je suis restée sckochée là dessus... mais au vu de la complexité des traitements il s'avère nécessaire de revoir l'hypothèse de départ...

Une bonne réponse, un bon verre de sauterne et voila, la vie prend une toute autre tournure ;o)

J'étudie tout ça et je reviendrai...

Bon réveillon et à bientôt et surtout n'oublions pas que s'il y a quelque chose à retenir c'es : "ne pas se compliquer la vie "!!!

MERCI et @+

par Ajoloca » 24 déc. 2006, 16:41

Bonjour,
Je n'ai pas lu ton dernier post avec attention mais je pense que tu te compliques la vie.

Pourquoi ne pas gérer un champ dans ta table "commandes" qui te dit si il est sauvegardé ou pas avec la date.

Ça te permet en une seule action de tout faire.
La seule chose qui change c'est ta requête.

par karpediem » 24 déc. 2006, 16:37

Re,

Après reflexion, la solution AUTO_INCREMENT ne me convient pas parce que dans ma configuration :

Tables source :
Parent - Enfant avec une cardinalité (0,n)

Tables cible :
Parent - Enfant avec une cardinalité (0,n)

Lorsque je vais vouloir ajouter les enregistrements de source.enfant dans cible.enfant il va falloir que je fasse la correspondance entre ancienne_id et nouveau_id. Si je laisse AUTO_INCREMENT pour cible.parent, je ne pourrait pas remettre en place la correspondance relationnelle ;-( A moins que je fasse mes INSERT 1 à 1... je crains que ce soit un peu long...

=> Retour à la case départ !

Il me reste 2 solutions :
- affecter au départ, à la création d'un enregistrement dans source.parent la bonne valeur d'identifiant qui pourrait être max(source.parent) + max(cible.parent). Le pb c'est que l'on va arriver à des valeurs énormes...

- affecter au moment de l'insert dans cible.parent et cible.enfant , la valeur d'identifiant qui pourrait être max(cible.parent) + 1 x num de l'occurrence à ajouter. Si 5 enregistrements à ajouter, je devrai faire : max(cible.parent) + (1 + 0), max(cible.parent) + (1 + 1), max(cible.parent) + (1 + 2) etc...
Cette solution me conviendrait mieux rapport aux valeurs obtenues et aussi parce qu'elle me semble moins sujette aux erreurs... et puis ça fait plus propre ;o)

De plus, je peux facilement construire un tableau dynamique avec ancien_id et nouveau_id.

Viens maintenant la question fatidique : comment SQL peut faire en 1 requete pour comprendre et faire ce que je souhaite... moi je ne vois pas comment construire mon instruction au vu de mes compétence basiques en SQL... associer un INSERT INTO avec un SELECT et VALUE je ne vois pô :-( => des idées ?

MERCI et @ bientôt.

par karpediem » 24 déc. 2006, 05:29

Re,

Je crois qu'en ce qui concerne l'utilisation de PDO (entre autre ;o), il va falloir que je retourne en formation ;-)

Bon, je vais essayer avec AUTO_INCREMENT, je teste tout ça et je te tiens au courant.

MERCI pour ton aide et toutes ces infos et @ bientôt.

Karpediem

par Ajoloca » 24 déc. 2006, 05:20

Pour les réponses du forum 99% des fois mysql_* que j'ai jamais utilisé personnellement.
J'ai utilisé mysqli mais en tant que objet $cnx = new mysqli(....), depuis PHP 5.x j'utilise PDO.

par karpediem » 24 déc. 2006, 05:15

re,

Ma remarque : mysql_result fonctionne avec mysql_query...

c'est pare ce que tu as écrit :
$qryMaxCmde = "SELECT MAX(num_commande) AS max_commande FROM sauv_commande";
$result = mysql[size=150]i[/size]_query($_POST['link'], $qryMaxCmde) || die ('ERR_SQL :<br />' . $qryMaxCmde . '<br />' . mysql_error());
return(mysql_result($result, 0, 0));
Tu as dû faire un copier/coller de ce que j'avais écrit...

Cette précision était destinée à ceux qui pourraient lire ce post et s'en servir en faisant également un copier/coller ;o)

Au fait, moi j'ai pris l'habitude d'utiliser mysqli_connect au lieu de mysql_connect car au cours de ma formation on m'avait dit que c'était mieux, mais je ne me souviens plus pourquoi... toi tu utilises quoi ?

@ +

par Ajoloca » 24 déc. 2006, 05:03

Une remarque : mysql_result fonctionne avec mysql_query...
:?:
pas compris !

Au lieu de faire un SELECT * tu fais un SELECT champ par champ et le résultat est le même sans modifier la valeur de l'AUTO_INCREMENT de destination.

par karpediem » 24 déc. 2006, 04:57

Re,

L'instruction TRUNCATE TABLE ne me va qu'à moitié car tous les enregistrements ne sont pas forcément sélectionnés...

Je me souviens pourquoi j'ai mis en place cette double numérotation... Lors de l'insertion d'un enregistrement dans ma table "temporaire" (table_tempo) je ne peux pas lui affecter sa valeur définitive car si je récupère max(table_sauvegarde), cette valeur va rester stable alors que je continue d'ajouter des enregistrements dans ma table_tempo. La valeur de ma clé serait : max(table_tempo) + max(table_sauvegarde)...

C'est pour cela que la solution AUTO_INCREMENT me semble intéressante... Dans ce cas, l'instruction :

INSERT INTO sauv_commandes (SELECT * FROM commandes WHERE num_commande IN (num1, num2, .....));

est-elle toujours adaptée alors que dans le SELECT * on récupère le champs clé qui est auto_incrementé par rapport à sa propre table et on l'ajoute dans une autre ? il renomme automatiquement toute insertion même si on lui donne explicitement une valeur pour la clé ?

Une remarque : mysql_result fonctionne avec mysql_query...

par Ajoloca » 24 déc. 2006, 04:39

Reprenons,

Une fois les informations qui t'intéressent (on va les appeler comme ça et pas commandes)
de ta table d'origine sauvegardées tu recommences à 1, c'est bien ça ?

Dans ce cas un TRUNCATE TABLE (de la table originale) serait la chose la plus appropriée.

Il est évident que si la valeur de la clé n'a pas d'importance et quelle est la pour l'unicité, le AUTO_INCREMENT serait plus adapté (dans les deux tables).

par karpediem » 24 déc. 2006, 04:30

re,

je viens de tester mysql_result => super cool ça fonctionne super...

concernant mes commandes, je crois que la solution c'est d'inserer dans commande des enregistrements avec dès le depart la bonne valeur (par rapport à sauv_commande) et ne pas raisonner sur l'idée que c'est une table temporaire avec des enregistrement numérotés de 1 à n...

j'y reflechi et je vois si par rapport aux autres traitements ça ne pose pas de pb...

par karpediem » 24 déc. 2006, 04:19

Bonjour,

Concernant les tests de retour, je les fait, mais je n'ai pas voulu surcharger mon message deja bien long ;o)

La raison pour laquelle je renomme mes commandes, c'est parce qu'une fois que toutes mes commandes ont été sauvegardées, donc supprimées de ma table commande et copiées dans sauv_commande, mes numeros de commande repartent à 1. Dans la réalité mes enregistrements ne concernent pas des commandes, mais j'ai utilisé commande dans ce message histoire de conceptualiser...

Ma table commande n'est qu'une table de travail qui est là, le temps de la vérification des informations...

Par ailleurs, ma table sauvegarde sera vidée mensuellement de tout ce qui a plus d'un mois.

L'identifiant de la commande n'est là que pour assurer l'unicité mais ne correspond à aucune réalité telle que un numéro de commande...

Peut-être que l'identifiant auto_incrementé prend justement de son sens dans ce contexte...

Concernant le INSERT, tant qu'il n'y a pas de mise à jour, ça ne me pause pas grand pb, mais ce que je souhaiterai faire c'est quelque chose dans le genre :

SELECT * FROM commandes WHERE num_commande IN (num1, num2, .....
INSERT INTO sauv_commandes avec un num_commande UPGRADé tel que (num1 = nouveau_num1, num2= nouveau_num2, .....

le tout dans une seule requete bien-sûr ;o))

@ +

par Ajoloca » 24 déc. 2006, 03:48

Bonsoir,

Je crois qu'il va falloir procéder par étapes.

Pour ta première question, pas trop de PB.
Une remarque tout de même. Il faut toujours tester le retour d'une requête!!!
$qryMaxCmde = "SELECT MAX(num_commande) AS max_commande FROM sauv_commande";
$result = mysqli_query($_POST['link'], $qryMaxCmde) || die ('ERR_SQL :<br />' . $qryMaxCmde . '<br />' . mysql_error());
return(mysql_result($result, 0, 0));
Pour la suite, je trouve des choses bizarres.
Un numéro de commande ne peut être changé ! (ça c'est la loi)
donc quand tu sauves tes commandes tu ne devrais pas t'occuper de la valeur de la table sauv_commande,
Tu dois logiquement reprendre celui de commandes.

Pour ton insertion, c'est relativement simple.
Une fois que tu as récupéré les numéros des commandes à sauvegarder,
tu construis une requête du style (la syntaxe est à vérifier)
INSERT INTO sauv_commandes (SELECT * FROM commandes WHERE num_commande IN (num1, num2, .....));
Et dans le même style pour tes lignes de commande.

Comme tu as toujours en ta possession les numéros de commande que tu a sauvegardé, tu fais un delete avec le même type de requête
DELETE FROM commndes WHERE num_commande IN (num1, num2, ...);

Effectuer un INSERT associé à SELECT et UPDATE + auto_increm

par karpediem » 24 déc. 2006, 02:59

Bonjour,

Me revoilou...

Je vous explique le contexte :

- J'ai une table Mysql que je vais appeler SAUV_COMMANDE et une autre SAUV_LIGNE. Les numéros de commande sont numérotés de 1à n.

- J'ai 2 autres tables de la même structure que les précédentes que je vais appeler COMMANDE et LIGNE. Les numéros de commande sont numérotés de 1 à p.

- Sur mes tables (2 à 2) j'ai un DELETE ON CASCADE et UPDATE ON CASCADE...

ah oui, mes compétences SQL sont basiques ;o)

Je propose dans mon application une option "sauvegarder les commandes" avec le choix des commandes à sauvegarder.

Pour cela, j'ai un formulaire qui affiche tous les enregistrements de ma table COMMANDE (dans un tableau suite à une requete SELECT * FROM commande) et pour chaque enregistrement, j'ajoute une case à cocher qui récupére le num_commade, c'est-à-dire l'identifiant de la commande.
Jusque là, pas de pb...

L'utilisateur checke les commandes qu'il souhaite sauvegarder et demande la sauvegarde des commandes sélectionnées. En terme de traitement, voila ce que je fais :

- 1ere étape :
je récupère le dernier num_commande de la table SAUV_COMMANDE (je simplifie les controles afin de ne garder que l'essentiel).

$result = mysqli_query($_POST['link'], "SELECT MAX(num_commande) AS max_commande FROM sauv_commande"))

while ($row = mysqli_fetch_assoc($result))
{
return $row['no_commande'] ;
}

Une 1ere question => je n'ai pas trouvé 1 autre moyen que la boucle while pour lire le résultat alors qu'il n'y a qu'une ligne... avez-vous une autre solution plus optimale (même si celle-ci fonctionne bien) ?

- 2eme étape :
Je construits un tableau dynamique avec la liste des num_commande qui ont été sélectionnés et la nouvelle valeur = (max_commande + 1) en indice (ça, ça fonctionne aussi). Je récupère par la même occasion le nombre de commandes à traiter...
Je construits aussi (boucle for) une chaine $check avec la liste des num_commande à traiter pour les requetes SQL sous la forme : num_commande = $tab[0] OR num_commande = $tab[1] OR etc.
et une chaine $check2 dans le même esprit mais avec les nouvelles valeurs : max_commande + n.

- 3eme étape :
C'est là que je commence à bidouiller ;-(

L'idée est d'inserer dans SAUV_COMMANDE, les enregistrements chéckés de COMMANDE en leur affectant un num_commande qui va bien, c'est à dire pas celui qu'ils ont dans COMMANDE mais à la suite de celui récupéré à l'étape 1 (max de sauv_commande) pour une incrémentation suivie.

Voila la bidouille (même si ça fonctionne) que j'ai trouvé (ne criez pas ;o) :
$sql1 = "UPDATE commande SET num_commande = 1 + ".$max_commande." WHERE".$check;

$sql2 = "INSERT INTO sauv_commande SELECT * FROM commande WHERE".$check2;

$sql3 = "INSERT INTO sauv_ligne SELECT * FROM ligne WHERE".$check2;

puis enfin :

$sql4 = "DELETE FROM commande WHERE".$check2;

Algorithmiquement parlant ça fonctionne et mon traitement au final est OK, mais j'y vois plusieurs pb :

1. L'instruction UPDATE...
Idéalement, je devrais pouvoir faire un INSERT INTO sauv_commande avec directement le bon num_commande sans avoir à modifier la clé de ma table commande (on n'aime pas avoir à modifier les clés !).

Là je ne sais pas faire pour un INSERT associé à un UPDATE pour faire plusieurs insertions en 1 seule opération avec un SELECT => quelqu'un aurait-il une suggestion ?

Par ailleurs, j'ai bien pensé à faire un champ AUTO_INCREMENT pour mes tables commande et sauv_commande afin de ne pas avoir à gérer l'incrementation du num_commande et éviter le UPDATE. Mais ça génère une autre question : dans le INSERT, la valeur de num_commande devrait être à NULL non ? mais là aussi, dans le cas d'un INSERT multiple (associé à un SELECT), je ne sais pas comment ecrire cette instruction...

Pour résumer :

- Est-il possible de remplacer $sql1 et $sql2 (et après $sql3) en 1 unique requete qui ferait un INSERT INTO sauv_commande AVEC les enregistrements chéckés dans commande avec num_commande = max_commande + n ?

ou autre solution :

- Utiliser des champs AUTO_INCREMENT pour les num_commande et là comment écrire les requêtes $sql1 et $sql2 (et après $sql3) avec une valeur NULL pour la clé ?

Dernière question => laquelle de ces 2 solutions vous parait-elle la plus optimales, si non avez-vous une solution encore plus optimisée ?

Ouf c'est fini !!! En comtre partie, j'espère avoir été assez claire ;o))

Merci à tous ne serait-ce que pour avoir supporté ma prose jusqu'au bout ;o))

J'accepte bien évidemment toute critique sur ma methodo ;o))

@ bientôt[/php]