Requete ok sous PHP4, et ne fonctionne plus sous PHP5

page 1 page 2
Répondre
Sammuel
Sammuel
Déconnecté
Salut ! C'est encore moi smiley

J'ai une requête qui ne veux plus fonctionner sous PHP5 ! Sous PHP4, elle fonctionnait très bien ! meme si je me demandais comment MYSQL pouvait s'y retrouver avec ^^

La requête est la suivante :
  1. SELECT marque.idmarque,marque.marque,modele.idmodele,modele.modele,COUNT(voiture.idvoiture) AS total
  2. FROM marque,modele
  3. LEFT JOIN voiture ON voiture.idmarque = marque.idmarque
  4. WHERE marque.idmarque = modele.idmarque
  5. GROUP BY marque.marque,modele.modele
  6. ORDER BY marque.marque,modele.modele ASC 


Les tables :
  1. Marque (idmarque / marque)
  2. 1 Renault
  3. 2 Citroen
  4. 3 Peugeot
  5. ...
  6.  
  7. Modele (idmodele / idmarque / modele)
  8. 1 1 Clio
  9. 2 1 Scenic
  10. 3 2 Xsara
  11. 4 2 Saxo
  12. 5 3 306
  13. ...
  14.  
  15. Voiture (idvoiture / idmarque / idmodele / serie)
  16. 1 1 1 Clio 1
  17. 2 1 1 Clio 2
  18. 3 3 5 306 phase 1
  19. 4 3 5 306 phase 2
  20. ...
  21.  
  22. PS : J'ai inclus l'idmarque dans la table voiture pour éviter de faire trop de jointures entre les tables, car il y aura beaucoup d'enregistrements dans cette table... + d'1 million 


Voyez vous un problème dans la requête ? car MYSQL me retourne cette erreur :
  1. #1054 - Unknown column 'marque.idmarque' in 'on clause' 


Apparemment, MYSQL n'arrive pas à faire de lien entre la table 'marque' et 'voiture' dans le LEFT JOIN. Pourtant sous PHP4, ca fonctionné ^^

Peut être que je dois activer quelque chose dans le php.ini pour que ça fonctionne ? smiley
LA GLOBULE
LA GLOBULE
Déconnecté
111 111 111 x 111 111 111 = 12 345 678 987 654 321
Ben tu as juste une erreur SQL, ca n'a rien à voir avec la version de PHP.

Et l'erreur est simple : MySQL ne connait pas le champ "marque.idmarque".
Ensuite, il faudrait voir la structure réelle de tes tables et non une explication en francais de ton schéma de base. Genre un dump de phpmyadmin sur la structure des tables.
Tu n'aurais pas une faute d'orthographe sur le nom de ton champ ? (genre il ne serait pas écrit pareil en base et dans la requête).
Sammuel
Sammuel
Déconnecté
non aucune erreur d'accent.

Avant, j'utilisais Easyphp 1.7 en local sous windows avec :
Apache 1.3.27
PHP 4.3.3
Phpmyadmin 2.5.3
Mysql 4.0.15

Et quand j'exporte la bdd, cela me retourne :
  1. CREATE TABLE `marque` (
  2. `idmarque` int(2) NOT NULL auto_increment,
  3. `marque` varchar(50) default NULL,
  4. PRIMARY KEY (`idmarque`)
  5. ) TYPE=MyISAM AUTO_INCREMENT=5 ; 


Aujourd'hui, j'utilise WAMP5 en local avec :
Apache 2.2.6
PHP 5.2.5
MYSQL 5.0.45

Et quand j'exporte la bdd, cela me retourne :
  1. CREATE TABLE `marque` (
  2. `idmarque` int(2) NOT NULL auto_increment,
  3. `marque` varchar(50) default NULL,
  4. PRIMARY KEY (`idmarque`)
  5. ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ; 


Donc peut etre que le probleme est lié au CHARSET ?? car maintenant, sous WAMP, j'ai une colonne 'Interclassement' avec 'latin1_swedish_ci' de mentionner dedans.
Sammuel
Sammuel
Déconnecté
Sous WAMP5, j'ai fait un test d'importation de la bdd en latin1, en UTF8, mais ça ne change rien. Idem quand je spécifie le format d'importation en MYSQL 4.

La requête affiche toujours la même erreur.

J'ai essayé de renommé la table, puis de la re renommer 'marque'. Ca ne change rien.

C'est bien MYSQL qui n'arrive pas à faire le lien entre la table voiture et marque.
Sammuel
Sammuel
Déconnecté
Je viens de trouver ca :
http://www.oscommerce-fr.info/faq/qa_info.php?qID=198

Je continue a chercher ;)
Sammuel
Sammuel
Déconnecté
tss...

J'ai simplement ajouté des () dans FROM et ca fonctionne :
  1. SELECT marque.idmarque,marque.marque,modele.idmodele,modele.modele,COUNT(voiture.idvoiture) AS total
  2. FROM (marque,modele)
  3. LEFT JOIN voiture ON voiture.idmarque = marque.idmarque
  4. WHERE marque.idmarque = modele.idmarque
  5. GROUP BY marque.marque,modele.modele
  6. ORDER BY marque.marque,modele.modele ASC 


mdr... je ne vois pas trop l'intéret de faire ca, mais si ca peut leur faire plaisir smiley

En tout cas, l'erreur retournée n'est pas du tout explicite !!
LupusMic
LupusMic
Déconnecté
Développeur récurrent, procédural et relationnel. Caustique soupe-au-lait.
Pourquoi limiter à 100 le nombre de marques ? N'oublie pas que la pire des optimisation, c'est celle qui créé des bogues. Si vraiment ça commence à ramer, il sera toujours temps d'optimiser.

Ta requête ne passait plus parce que MySQL 5 ne comprend pas le SQL comme le comprenait MySQL 4. D'ailleurs, je le comprends, le pauvre.

Pour comprendre ce qui se passe, il faut extraire le morceau suivant :
  1. modele LEFT JOIN voiture ON voiture.idmarque = marque.idmarque 


L'erreur retournée est parfaitement explicite. Dans ce code, MySQL fait une jointure sur les table modele et voiture. À ce moment, l'interpréteur ne connait aucune autre table. Ainsi la table marque, on connait pas. D'ailleurs, c'est une erreur de faire intervenir la table marque.

En mettant des parenthèse autour des deux tables, tu grille la priorité au left join en forçant la première jointure. Ce qui créé une table dans laquelle la colonne souhaitée dans le on clause existerait. Certes ça marche, mais question performances... j'ai des doutes sérieux.

Je repose les tables à ma convenance (pour faire des essais), et réécrit la requête que tu semble souhaiter. Au fait, dans la table voitures, le champs marque_id est malvenu. À mon avis. Et si vraiment il y a besoin d'optimiser, il faudra se poser les questions à ce moment.

  1. create table marques (
  2. id int(11) NOT NULL auto_increment,
  3. marque varchar(255) default NULL,
  4. primary key (`id`)
  5. ) engine='InnoDB' ;
  6.  
  7. create table modeles
  8. ( id int(11) NOT NULL auto_increment
  9. , modele varchar(255) default NULL
  10. , marque_id integer
  11.  
  12. , primary key (`id`)
  13. , foreign key (marque_id) references marques(id)
  14. ) engine='InnoDB' ;
  15.  
  16. create table voitures
  17. ( idint(11) NOT NULL auto_increment
  18. , label varchar(255) default NULL
  19. , modele_id integer
  20.  
  21. , primary key (`id`)
  22. , foreign key (modele_id) references modeles(id)
  23. ) engine='InnoDB' ;
  24.  
  25. explain
  26. select
  27. marques.id as marque_id
  28. , marques.marque as marque
  29. , modeles.id as modele_id
  30. , modeles.modele as modele
  31. , count(voitures.id) as total
  32. from voitures left join modeles on voitures.modele_id
  33. left join marques on modeles.marque_id
  34. group by marque, modele
  35. order by marque, modele asc ; 


Et puis un conseil : du SQL en aveugle, c'est casse-gueule. Tu devrais lire la documentation de MySQL in extenso pour vraiment maîtriser ces arcanes (ce que je suis loin de pouvoir assurer pour moi ;) ).
Sammuel
Sammuel
Déconnecté
Merci pour ton aide LupusMic ;)

C'est vrai que je fais du SQL a la bonne franquette même si j'essaie de limiter le nombre de requêtes et essaie de les simplifier au maximum.

J'avais l'intention d'acheter des livres à ce sujet... mais je peux surement trouver tout ce qu'il me faut sur internet !

Je vais tester ta requete, tes tables, et je te tiens au courant !
Sammuel
Sammuel
Déconnecté
J'ai oublié de préciser que j'ai toujours utilisé MyISAM comme moteur SQL. Et comme je comptais utiliser FULL TEXT pour faire une recherche au niveau du nom des voitures par exemple, ou au niveau de leurs descriptions, ça ne va pas fonctionner avec InnoDB !

La fonction recherche sur mon site est une fonction principale pour naviguer dessus (50/75% d'utilisation)... un peu comme un moteur de recherche en fait :) Donc, c'est surtout a ce niveau qu'il faut que j'optimise. Je comptais donc utiliser FULL TEXT !

Existe t'il un moyen d'optimiser une recherche via InnoDB ? à l'instar du FULL TEXT avec MyISAM ?
LA GLOBULE
LA GLOBULE
Déconnecté
111 111 111 x 111 111 111 = 12 345 678 987 654 321
Tu te contredis la : tu dis utiliser MyISAM, et tu veux faire du FULLTEXT.
Et ben justement, le FULLTEXT, c'est dispo avec MyISAM.

Donc je ne vois pas pourquoi tu parles d'innoDB la.

Ensuite, comment faire la même chose que le FULLTEXT en innoDB, ben il existe plusieurs solutions : dupliquer la table en MyISAM, ou créer un algo de recherche.
LupusMic
LupusMic
Déconnecté
Développeur récurrent, procédural et relationnel. Caustique soupe-au-lait.
(LA GLOBULE) C'est moi qui ai parlé d'InnoDB. J'ai l'habitude d'utiliser ce moteur en raison des contraintes de clé.
Sammuel
Sammuel
Déconnecté
LupusMic > Au niveau des recherches, tu utilises une technique spéciale avec InnoDB ? un algo de recherche ?

Peut etre pourrais tu m'aiguiller niveau algo de recherche PHP ? smiley. Je vais essayer de trouver quelque chose à ce sujet...

Merci !
Sammuel
Sammuel
Déconnecté
Je vais déjà me tourner vers Phonex pour voir smiley
LA GLOBULE
LA GLOBULE
Déconnecté
111 111 111 x 111 111 111 = 12 345 678 987 654 321
Sammuel, tout comme Lupus mic, j'utilise beaucoup innodb (ne serait ce que pour les transactions), et pour le moteur de recherche du site, je duplique en fait mes tables en MyISAM avec un FULLTEXT.

Comment ca marche : quand un message est inséré dans mon forum, je l'insert dans une table innodb et je met aussi à jour d'autres tables, le tout dans une transaction. Ensuite, j'insere également le message dans une table MyISAM (et la, si la requete merde, ben elle merde, au pire les recherches du site seront moins précises, mais je perds pas l'intégrité de ma base principale innoDB).

Les raisons de ce choix :
- simplicité de mise en place
- faible cout CPU lors des recherches
- j'ai une petite base de données à la base (sans table dupliquée) et donc ma base n'est pas forcement beaucoup plus grosse avec ces tables dupliquées (la base pour lephpfacile : 100 Mo environ).

PS : cette technique était utilisée par wikipedia il n'y a pas ci longtemps que ca. Eux par contre, ils remplissaient les tables MyISAM toutes les nuits au lieu de les remplir à chaque insertion d'article => leur recherche était moins précise jusqu'à ce que la nuit arrive, mais le lendemain, la recherche donnait tous les résultats possibles.
PPS : les deux techniques sont combinables => tu peux insérer dans la table MyISAM au fur et à mesure et lancer toutes les nuits un script qui calculera le diff entre les deux tables et compléter la table MyISAM.
LupusMic
LupusMic
Déconnecté
Développeur récurrent, procédural et relationnel. Caustique soupe-au-lait.
Et pour encore simplifier les choses, et rendre l'opération atomique, on peut imaginer remplir la table MyISAM depuis une procédure stockée appelée via un trigger.
page 1 page 2
Répondre
Accès rapide :

Remonter Remonter
L'éditeur javascript - CSS - Gentoo - Tutoriaux PHP - Tutoriels PHP - Php - Breizh Blog