Ordre requête SQL (2eme question)

devlop78
Invité n'ayant pas de compte PHPfrance

08 janv. 2011, 02:33

J'en profite de poser une autre question, car elle n'est largement pas sans rapport.

J'ai une table Ticket

id PRIMARY
job VARCHAR (6)
statut BOOL

Une table Ticket_comm

id PRIMARY
id_ticket INT
commentaire VARCHAR (200)
date TIMESTAMP

ENfin, grosso Modo, les détails sont inutiles, mais la relation Ticket_comm/Ticket est de type 1:n

Dans le meilleur des mondes, tout est déjà dans l'ordre. Actuellement, dans une jointure, Ticket est selectionnée avant Ticket_comm, j'ai donc un affichage des tickets dans l'ordre de création, ainsi que leurs commentaires. Ceci dit, si MySQL utilise l'ordre qu'il veut de selection des tables, il faudrait certainement lui dire de commencer par Ticket. Ca, de toutes façons, quoiqu'il arrive.

Ensuite, j'avais déjà remarqué que les "id" ne se suivait pas toujours. Ayant mon idée sur la question (et logique derrière cela), j'ai donc, il y a 5 minutes, créé une table dans lequel j'ai mis 6 enregistrements. J'en ai supprimé deux au milieu, et j'en ai rajouté deux autres. Effectivement, les deux rajoutés se sont placés là où étaient ceux que j'ai supprimé. J'ai donc :

1, 8, 7, 4, 5, 6

Je ne peux donc pas me fier à l'ordre des lignes utilisées par MySQL, du moins pas dans cet état. Car, sans cette méthode d'optimisation de place, mes Tickets et commentaires sont déjà placé par ordre chronologique.

Donc, une autre question : faut-il replacer ces identifiants après chaque DELETE, ou dans la requête SELECT. J'ai sincèrement déjà la réponse : DELETE. Malgré cela, (... j'allais dire une grosse bêtise (oui je réfléchis en même temps que j'écris)) .. pas de malgré. Il existe effectivement bien un trigger DELETE. Donc Ok. Maintenant, considérons que je souhaite passer par un SELECT... Suite au prochain numéro car la date du ticket se trouve dans son premier commentaire ... :oops:

Modérateur PHPfrance
Modérateur PHPfrance | 2575 Messages

13 janv. 2011, 19:52

Dans tous les cas logiquement un Ticket doit avoir une date/heure qui assure la chronologie de cette information par rapport aux autres Tickets et pour lister les tickets dans le temps il suffit d'un ORDER BY sur le champ date de ticket dans un SELECT.
--------//////----//---//----//////
-------//---//----//---//----//---//
------//////----//////-----//////
-----||--------||--||---||
Prendre le recul n'est pas une perte de temps.


ps: Affrontez moi dans l'arène

devlop78
Invité n'ayant pas de compte PHPfrance

14 janv. 2011, 01:41

Non, la table Ticket ne contient pas d'heure, et ce n'est pas utile. C'est une information redondante. Concernant le ORDER BY, on en revient au problème de la question n°1. Si je fais :

SELECT * FROM (SELECT * FROM Ticket INNER JOIN Ticket_com ON Ticket_com.id_ticket = Ticket.id WHERE Ticket.job_id = 'C000000' ORDER BY Ticket_com.date ASC) A GROUP BY A.id ORDER BY NULL

=> En gros, je vais chercher le Ticket_com le plus vieux pour chaque Ticket (et joint au ticket), et ça met les ticket dans l'ordre. Il me faudrait, et j'ai souvent ce besoin), de chercher un équivalent de LIMIT x,y mais pour chaque groupe (par exemple, chercher le deuxieme ticket le plus vieux).

Pour avoir la liste de mes tickets dans l'ordre. Il faut ensuite que je l'insère en sous requête pour aller chercher mes messages de Tickets. Il y a peut-être plus simple (mais là c'est plus l'heure ^^), et surtout le WHERE limite beaucoup l'utilisation des ressources. L'utilisation de l'ordre initial éviterait de toutes façons de faire aussi compliqué (bien que j'ai fait ça toute la journée). Par contre, MySQL, les triggers et moi sommes fachés car impossible d'en créer un, surtout quand je vois que OPTIMIZE ne peut pas être utilisé dans un trigger :evil:

Je souhaite quand même le confirmer !

ViPHP
ViPHP | 2577 Messages

14 janv. 2011, 10:05

Bonjour,

Je n'ai peut être pas tout compris mais un simple :

select * from Ticket, Ticket_com where Ticket.id = Ticket_com.id_ticket order by Ticket.id, Ticket_com.id

devrait suffire

Pour le group by, ca ne marche que pour restituer des colonnes présentes dans le group by et des colonnes utilisées avec des fonctions "inter lignes" comme max, sum...

devlop78
Invité n'ayant pas de compte PHPfrance

14 janv. 2011, 21:39

Bonjour,

Je n'ai peut être pas tout compris mais un simple :

select * from Ticket, Ticket_com where Ticket.id = Ticket_com.id_ticket order by Ticket.id, Ticket_com.id

devrait suffire

Pour le group by, ca ne marche que pour restituer des colonnes présentes dans le group by et des colonnes utilisées avec des fonctions "inter lignes" comme max, sum...
Oui ... cela serait fort bien si et seulement si les identifiants se suivaient. Ce qui est le cas maintenant, mais si on est amené à supprimer des Tickets, ceux supprimés laisseraient une place à de nouveaux, et l'identifiant ne serait plus une référence. D'où la question sur la possibilité de créer un trigger AFTER DELETE OPTIMIZE TABLE ...

Ce qui s'avère impossible à priori.

Mes questions sur les deux sujets ouverts reposent en fait non pas sur cette requête, qui, avec de l'expérience, sera plus optimisée et plus logique (comme l'ensemble des requêtes que je fais), mais sur :

- La possibilité de créer un trigger AFTER DELETE OPTIMIZE ou tout autre moyen automatique de réorganiser la table après chaque suppression, soit, par définition, un trigger.
- Le fonctionnement de STRAIGHT_JOIN qui me lit mes tables de droite à gauche, contrairement à tous les sites sur Google qui en parlent (mais qui se contentent de faire copier/coller de la doc de MySQL).
- Optionnellement, lors d'un groupage (ou pas), pouvoir choisir une position :

ex :

téléphone SIEMENS 12euros
téléphone SAMSUNG 15 euros
téléphone CASIO 8euros

=> SELECT Item2.prix FROM maTable Group by Type_appareil ORDER BY NULL

Où Item2 est en fait ma volonté de choisir ici "SAMSUNG" (c'est pas de la pub :p), sans le nommer, ni lui, ni son prix, mais bien pouvoir extraire des données du deuxième élément d'un groupage (ou le troisième, etc). J'ai déjà réussi à le faire, mais avec un long code SQL où je trouvais d'abord le premier, plus je l'éliminais de la liste pour chercher le premier restant ... soit le deuxième au final. Mais si je veux le 5ème, c'est pas tenable.

devlop78
Invité n'ayant pas de compte PHPfrance

17 janv. 2011, 01:41

Hmmmm ... Par contre, j'ai pensé à un truc :

ALTER TABLE xxx ORDER BY `id`

En testant, le alter Table retrie l'ensemble de la table. Et quand on ajoute une ligne après en avoir supprimé, elles se remettent à la fin ... Donc l'idée serait de ne pas faire le OPTIMIZE mais le ALTER.

devlop78
Invité n'ayant pas de compte PHPfrance

17 janv. 2011, 04:32

- Optionnellement, lors d'un groupage (ou pas), pouvoir choisir une position :
Hmmm ... trouvé. Enfin trouvé sur quelque chose de simple

SELECT C.evenements FROM (SELECT A.evenements,A.commandeNum FROM maTable A, maTable B WHERE A.evenements < B.evenements AND A.commandeNum = B.commandeNum ORDER BY A.evenements DESC) C GROUP BY C.commandeNum

Ainsi, si on a

commandeNum | evenements
1 | 50
1 | 25
1 | 10
2 | 12
2 | 48
2 | 16

On aurait bien 25 pour la commande 1 et 16 pour la commande 2 qui seront sélectionnés. Enfin, à cela il faut rajouter une jointure avant car les nombre "evenements" sont déjà le résultat d'une jointure ...

Pour l'autre question, j'ai aussi à priori trouvé (il faut faire une pause, et ça vient tout seul :p), mais pour les Tickets, je ne vois pas de solution miracle.

devlop78
Invité n'ayant pas de compte PHPfrance

17 janv. 2011, 04:52

Héhé ... il m'en a fallu du temps ...

Je crois avoir trouvé (non testé) :

SELECT ... FROM (SELECT * FROM (SELECT Tickets_com.date, Tickets.id FROM Tickets_com JOIN Tickets ON Tickets.id = Tickets_com.id_ticket ORDER BY Tickets_com.date) T GROUP BY T.date ORDER BY NULL) Tickets_avec_date JOIN Tickets_com ... ORDER BY Tickets_avec_date.date, Tickets_com.date

Encore une fois, il ne faut pas que je réfléchisse en terme de boucle mais bien avec ORDER BY. Je peux ainsi me passer de STRAIGHT_JOIN, et laisser l'optimiseur faire son boulot.

Par contre, en terme de performance, cela reste à voir, je pense même que cette requête là est plus gourmande en ressources.

ViPHP
ViPHP | 2577 Messages

17 janv. 2011, 10:55

Bonjour,

Sauf erreur de ma part, les id sont créés de manière croissante en cas d'autoincrément. Le fait de mettre "order by id" permet d'avoir les plus anciens en premier. Cela n'a pas d'impact sur le fait qu'un select sans order by ne les retourne pas dans le bon ordre.

devlop78
Invité n'ayant pas de compte PHPfrance

17 janv. 2011, 13:12

Bonjour,

Sauf erreur de ma part, les id sont créés de manière croissante en cas d'autoincrément. Le fait de mettre "order by id" permet d'avoir les plus anciens en premier. Cela n'a pas d'impact sur le fait qu'un select sans order by ne les retourne pas dans le bon ordre.

Les id sont des séquences donc oui de manière croissante, mais elles peuvent se placer au milieu de la table si il y a de la place. Si une fois placée, je fais un simple SELECT, MySQL lira de la 1ere ligne à la dernière, et renverra de la même façon. Enfin, c'est toujours ce que j'ai eu, donc à moins qu'en théorie MySQL aie aussi le choix de l'ordre pour son optimisation, en pratique, sans order by, j'obtiens le plus ancien au plus récent (si pas de suppression)