Requête SQL complexe et éviter table temporaire

Requête SQL complexe et éviter table temporaire - SQL/NoSQL - Programmation

Marsh Posté le 05-03-2009 à 15:52:46    

Bonjour,
J'ai une grosse requête qui ne fonctionne pas encore sur MySQL 5.0.22.  
 

Code :
  1. SELECT a.AowID, a.AowDeadline, MIN( h.AowStatusHistoryDate ) AS minDate, MAX( h.AowStatusHistoryDate ) AS maxDate, st.AowStatusID, st.AowStatusOrder
  2. FROM (
  3. SELECT th.AowID, th.AowStatusID, th.SupportMemberID
  4. FROM (
  5. SELECT AowID, MAX( AowStatusHistoryID ) AS maxAowStatusHistoryID
  6. FROM AowStatusHistory
  7. GROUP BY AowID
  8. ) AS curHisto, AowStatusHistory th
  9. WHERE curHisto.maxAowStatusHistoryID = th.AowStatusHistoryID
  10. ) AS t
  11. LEFT JOIN SupportMembers affsm ON ( t.SupportMemberID = affsm.SupportMemberID ) , Aow a
  12. LEFT JOIN Customers c ON ( c.CustomerID = a.CustomerID )
  13. LEFT JOIN SupportMembers sm ON ( sm.SupportMemberID = a.SupportMemberID ) , Sites s, Subdivisions sub, Projects p, AowStatusHistory h, AowStatus st, (
  14. SELECT tcfv.CustomFieldValueID, tcfv.CustomFieldValueDate, tcfv.CustomFieldValueData, tcfv.CustomFieldID, tcfv.ObjectID
  15. FROM (
  16. SELECT ObjectID, CustomFieldID, MAX( CustomFieldValueID ) AS maxCustomFieldValueID
  17. FROM CustomFieldsValues
  18. GROUP BY ObjectID, CustomFieldID
  19. ) AS curHistoCF, CustomFieldsValues tcfv
  20. WHERE curHistoCF.maxCustomFieldValueID = tcfv.CustomFieldValueID
  21. ) AS cfv, CustomFields cf0, cfv AS cfv1, CustomFields cf1
  22. WHERE a.SiteID = s.SiteID
  23. AND a.SubdivisionID = sub.SubdivisionID
  24. AND a.ProjectID = p.ProjectID
  25. AND t.AowID = a.AowID
  26. AND h.AowID = a.AowID
  27. AND t.AowStatusID = st.AowStatusID
  28. AND cfv.ObjectID = a.AowID
  29. AND cf0.CustomFieldID = cfv.CustomFieldID
  30. AND cf0.CustomFieldName = "AowSite"
  31. AND cfv.CustomFieldValueData LIKE "3"
  32. AND cf1.CustomFieldID = cfv1.CustomFieldID
  33. AND cf1.CustomFieldName = "AowContactSite"
  34. AND cfv1.CustomFieldValueData LIKE "%test%"
  35. GROUP BY a.AowID


 
En fait, j'ai une table Aow à laquelle on peut ajouter des champs personnalisés (champs en plus des champs présents dans la table Aow). La table CustomFields contient entre autre l'ID et le nom (unique) de chaque champ personnalisé. La table CustomFieldsValues contient la ou les valeurs associées à chaque champ personnalisé et à une entrée dans la table Aow (jointure via le champ ObjectID qui contient la valeur de AowID). Un couple [champ personnalisé, ObjectID] peut avoir plusieurs valeurs dans le cas où le champ est paramétré pour historiser les changements de valeurs du champ.
 
Mon problème se situe au niveau de la partie "AS cfv, CustomFields cf0, cfv AS cfv1, CustomFields cf1". cfv, via une sous-requête, contient la dernière valeur de chaque couple [champ perso,ObjectID]. Quand je recherche sur 1 seul champ personnalisé, j'avais trouvé une requête qui fonctionnait. Mais si j'ai comme critères de recherche 2 champs personnalisés, je me retrouve à devoir multiplier les jointures sur mes tables liées aux champs personnalsiés et à leurs valeurs. Comem une sous-requête coûte cher en temps, je voudrais pouvoir dupliquer facilement le contenu de la table cfv pour pouvoir effectuer d'autres jointures dessus.
 
Avez-vous une solution, svp? Merci :jap:


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 05-03-2009 à 15:52:46   

Reply

Marsh Posté le 05-03-2009 à 17:22:11    

J'ai essayé de stocker le résultat de cette requête dans une table temporaire :

Code :
  1. (
  2. SELECT tcfv.CustomFieldValueID, tcfv.CustomFieldValueDate, tcfv.CustomFieldValueData, tcfv.CustomFieldID, tcfv.ObjectID
  3. FROM (
  4. SELECT ObjectID, CustomFieldID, MAX( CustomFieldValueID ) AS maxCustomFieldValueID
  5. FROM CustomFieldsValues
  6. GROUP BY ObjectID, CustomFieldID
  7. ) AS curHistoCF, CustomFieldsValues tcfv
  8. WHERE curHistoCF.maxCustomFieldValueID = tcfv.CustomFieldValueID
  9. ) AS cfv


Et ensuite de l'appeler plusieurs fois avec des alias différents mais en ça marche pas à cause d'une limitation de MySQL sur les tables temporaires :(
http://forums.mysql.com/read.php?20,198873
 
Là, je suis bien eu. Va falloir que je fasse plusieurs tables temporaires (une par champ personnalisé) :(...


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 05-03-2009 à 18:04:24    

Bon ben en créant 1 table temporaire par champ perso, ça marche, mais j'ai un peu peur des perfs par la suite quand ma table contenant les valeurs des champs perso va être pas mal remplie :(...
 
Vous n'auriez pas mieux à me proposer, svp?


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 09-03-2009 à 14:47:57    

up


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 20-03-2009 à 14:41:14    

Je viens seulement de voir ton PM.
 
Honnêtement, j'ai rien pigé à ton problème, et j'ai pas trop insisté tu me diras...
 
C'est quoi le souci ?
 
Genre tu cherches les lignes de ta table pour lesquelles tu as les champs personalisés "toto" et "titi" avec les valeurs respectives "1" et "2", c'est ça ? (et ceci avec un nombre indéfini de champs personnalités ?)

Reply

Marsh Posté le 20-03-2009 à 15:02:14    

oui, en gros, mais j'ai une table qui contient le paramétrage des champs personnalisés (ID, nom, type de valeur...), donc entre autre les nom "titi" et "toto" et une autre table qui contient leurs valeurs associées, un champ perso pouvant avoir plusieurs lignes dans cette table de valeurs si on a définit que les changements de valeurs du champ perso pouvaient être historisés.
 
Donc :
Table CustomFields
CustomFieldID
CustomFieldName
....
 
Table CustomFieldsValues
CustomFieldValueID      <- clé primaire
CustomFieldValueDate   <- date/heure à laquelle la valeur a été saisie
CustomFieldValueData   <- valeur du champ perso à une date donnée
CustomFieldID              <- Clé étrangère
ObjectID                     <- Clé étrangère pointant sur une autre table, ici, la table Aow, donc ObjectID pointe sur AowID
 
Table Aow (tickets)
AowID
AowRef
...
 
Aow contient des tickets (help-desk) et certains types de tickets peuvent avoir, en plus des champs définis dans la table Aow, des champs supplémentaires, dits champs personnalisés. Une ligne dans Aow peut avoir 0 ou plusieurs lignes dans CustomFieldsValues. Mon pb de pouvoir sortir la liste des tickets de la table Aow qui  ont pour champs personnalisés "toto" qui a comme valeur courante "1" et "titi" qui a comme valeur courante "2".
 
C'est plus clair?
 
Merci en tout cas de ton aide, mon pb est toujours d'actualité.


Message édité par rufo le 20-03-2009 à 15:04:17

---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 20-03-2009 à 16:00:08    

J'ai l'impression que le problème se trouve davantage au niveau du schéma relationnel qu'au niveau de la requête...  
 
SELECT A.AowID, CF.CustomFieldName, CFV.CustomVieldValueData FROM Aow A, CustomFields CF, CustomFieldsValues CFV WHERE CFV.ObjectID = A.AowID AND CFV.CustomFieldID = CF.CustomFieldID AND CF.CustomFieldName="titi" AND CFV.CustomFieldValueData="1"
 

Reply

Marsh Posté le 20-03-2009 à 16:11:20    

Ca ne va pas marcher car dans le cas de champs ayant leurs changements de valeur historisés, je vais avoir la première valeur et non la valeur courante (la dernière).


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 20-03-2009 à 17:42:04    

Non, c'est une jointure libre. Tu auras une ligne de résultats par valeur historisée.  
 
Si cependant tu ne veux que la dernière, rien ne t'empêche d'ajouter une condition sur une sous-requête, ou si un seul résultat t'intéresse, de faire un order by et un limit. Mais c'est plus laid que de profiter de la jointure.

Reply

Marsh Posté le 20-03-2009 à 18:04:06    

c'est ce que j'ai fait (voir mes requêtes postés précédemment). Mon pb est de pouvoir retrouver des enregistrements de la table Aow qui sont liés à plusieurs champs perso dont la dernière valeur de chaque champ perso vaut une valeur donnée par l'utilisateur (moteur de recherche).
Ta requête ne travaille que sur 1 champ perso, mois, j'en veux plusieurs.


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 20-03-2009 à 18:04:06   

Reply

Marsh Posté le 20-03-2009 à 18:05:57    

Et bien tu fais une simple jointure comme j'ai fait en retirant la condition et tu auras accès à tous tes champs personnalisés.

Reply

Marsh Posté le 20-03-2009 à 22:57:01    

Bon, apparemment t'as pas compris mon pb ou alors, le SQL, c'est pas ton truc. Je vais donc faire un ex concret.
Table Aow

Code :
  1. AowID |  AowRef    | ...
  2. 1     |  0903001   | ...
  3. 2     |  0903002   | ...
  4. 3     |  0903003   |


Table CustomFields

Code :
  1. CustomFieldID | CustomFieldName | CustomFieldHistoried | ...
  2. 1             | Site            | 0                    | ...
  3. 2             | Magasin         | 1                    | ...
  4. 3             | Contact         | 0                    | ...


Table CustomFieldsValues

Code :
  1. CustomFieldValueID | CustomFieldValueDate | CustomFieldData | CustomFieldID | ObjectID |
  2. 1                  | 2009-03-01 09:01:01  | "Site n°1"      | 1             | 1
  3. 2                  | 2009-03-01 09:01:01  | 5               | 2             | 1
  4. 3                  | 2009-03-01 09:10:15  | "Site n°3"      | 1             | 2
  5. 4                  | 2009-03-01 09:10:15  | 3               | 2             | 2
  6. 5                  | 2009-03-01 11:25:13  | 5               | 2             | 2
  7. 6                  | 2009-03-01 11:31:01  | 1               | 2             | 1
  8. 7                  | 2009-03-01 11:31:13  | 2               | 2             | 1
  9. 8                  | 2009-03-01 11:32:17  | "Toto"          | 3             | 3
  10. 9                  | 2009-03-01 11:32:17  | "Site n°2"      | 1             | 3


Donc j'ai 3 tickets dans ma table Aow. Tous les 3 ont, en plus de leurs champs dans la table Aow, des champs personnalisés. Les 2 premiers tickets (1 et 2) sont liés à 2 champs personnalisés (le 1 et le 2), le 3ième ticket est lié au champ perso n° 3. De plus, le champ personnalsié n°2 a ses changements de valeur historisés.
Dans mon moteur de recherche, je veux pouvoir lister les tickets (de la table Aow, donc)  qui ont comme valeur courante "Site%" pour le champ perso "Site" et comme valeur courante 5 pour le champ perso "Magasin". Le résultat est donc seulement le ticket n°2. Le ticket 1 ne correspondant pas car la valeur courante de son champ perso "Magasin" est 1 (bien qu'il soit passé à un moment donné à 5) et le ticket 3 n'est pas lié au champ perso "Magasin".
 
C'est plus clair, là? Tu vois donc que ta requête n'est pas bonne.

Message cité 2 fois
Message édité par rufo le 22-03-2009 à 20:46:01

---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 21-03-2009 à 00:23:42    


 
Select Aow.*
From Aow inner join  
 (
 select  
  CF.CustomFieldID ,
  CF.CustomFieldName ,
  max(CFV.CustomFieldValueDate) as CustomFieldValueDate ,
  CFV.ObjectID
 from  CustomFields CF inner join CustomFieldsValues CFV
  on CF.CustomFieldID = CFV.CustomFieldID
  and  (  (CF.CustomFieldID = 1 and CFV.CustomFieldData like 'Site%')  
  or  (CF.CustomFieldID = 2 and CFV.CustomFieldData = '5')  
  )
 group by  
  CF.CustomFieldID ,  
  CF.CustomFieldName ,  
  CFV.ObjectID
 ) A
 on Aow.AowID = A.ObjectID
 

Reply

Marsh Posté le 21-03-2009 à 00:32:55    

rufo a écrit :

Bon, apparemment t'as pas compris mon pb ou alors, le SQL, c'est pas ton truc. Je vais donc faire un ex concret.


Ou peut-être pourrais-tu envisager le fait que tu n'aies pas expliqué clairement ton problème ?

Reply

Marsh Posté le 21-03-2009 à 02:15:52    

kler! t'es un peu brut de pomme rufo ! :-)

Reply

Marsh Posté le 21-03-2009 à 09:59:33    

guybrush02 a écrit :


Ou peut-être pourrais-tu envisager le fait que tu n'aies pas expliqué clairement ton problème ?


 
Désolé pour mon énervement, mais tu m'as proposé des requêtes tellement simple que que si mon pb était si simple, je ne serais pas venu exposer mon pb ici (et j'aurais pas appelé MagicBuzz à l'aide par MP). T'as vu la tronche de ma première requête : sans être un pro du SQL, je ne suis pas non plu un débutant ;)
 
Et effectivement, je me suis douté que je ne m'étais peut-être pas assez bien exprimé, d'où mon ex.


Message édité par rufo le 21-03-2009 à 10:00:26

---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 21-03-2009 à 10:12:48    

akario a écrit :


 
Select Aow.*
From Aow inner join  
 (
 select  
  CF.CustomFieldID ,
  CF.CustomFieldName ,
  max(CFV.CustomFieldValueDate) as CustomFieldValueDate ,
  CFV.ObjectID
 from  CustomFields CF inner join CustomFieldsValues CFV
  on CF.CustomFieldID = CFV.CustomFieldID
  and  (  (CF.CustomFieldID = 1 and CFV.CustomFieldData like 'Site%')  
  or  (CF.CustomFieldID = 2 and CFV.CustomFieldData = '5')  
  )
 group by  
  CF.CustomFieldID ,  
  CF.CustomFieldName ,  
  CFV.ObjectID
 ) A
 on Aow.AowID = A.ObjectID
 


 
Cette requête ne répond juste à tous les coup à mon pb à cause du OR. En effet, les tickets qui vont avoir juste 1 seul champ perso ayant la bonne valeur seront aussi retournés et moi, je veux que seuls les tickets répondant à tous les critères sur les champs perso soient retournés. Petit indice : à ma connaissance (si y'a une autre technique, je suis preneur), quand on veut faire des jointures sur plusieurs ligne d'une même table mais avec des conditions différentes portant sur un même champ (ici, je veux les champs persos dont le nom est "Site" ou "Magasin" mais les tickets doivent être liés à ces 2 champs), on doit ouvrir plusieurs fois la même table :

Code :
  1. SELECT ... FROM Aow a, CustomFieldsValues cfv1, CustomFieldsValues cf2, CustomFields cf1, CustomFields cf2 WHERE cfv1.CustomFieldID = cf1.CustomFieldID AND cf1.CustomFieldName = "Site" and cfv1.CustomFieldData Like "Site%" AND cfv1.ObjectID = a.AowID AND cfv2.CustomFieldID = cf2.CustomFieldID AND cf2.CustomFieldName = "Magasin" and cfv2.CustomFieldData = "5" AND cfv2.ObjectID = a.AowID


Maintenant, y'a plus qu'à faire en sorte que les CustomFieldData pointent sur la dernière valeur (leur valeur courante) de chaque champ perso et ce sera bon. Et pour faire ça, faut passer par une sous-requête et le résultat de cette sous-requête, faut le dupliquer pour chaque champ perso (d'où mes tables temporaires) : et c'est là que ma méthode, je la trouve pas terrible et que j'aimerais en avoir une meilleure ;)


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 21-03-2009 à 10:29:09    

Tu peux toujours remplacer une table tempo par un select imbriqué

Reply

Marsh Posté le 21-03-2009 à 10:30:52    

pour que "CustomFieldData pointent sur la dernière valeur", utilise :
 
 select  
  CF.CustomFieldID ,
  CF.CustomFieldName ,
  max(CFV.CustomFieldValueDate) as CustomFieldValueDate ,
  CFV.ObjectID
 from  CustomFields CF inner join CustomFieldsValues CFV
  on CF.CustomFieldID = CFV.CustomFieldID
  )
 group by  
  CF.CustomFieldID ,  
  CF.CustomFieldName ,  
  CFV.ObjectID
 
ensuite fait ta jointure avec tes tickets de la table Aow, puis greffe tes conditions sur le resultat dans ta clause where
 
rien de bien compliqué
 


Message édité par akario le 21-03-2009 à 10:32:13
Reply

Marsh Posté le 21-03-2009 à 11:51:50    

Pour te faciliter la vie, est il possible de rajouter un champ dans la table des CustomFieldData ?
Tu pourrais ajouter un IS_LAST qui vaudrait 1 pour les dernieres valeurs et 0 pour toutes les valeurs historisées.
Tu n'as plus qu'a ajouter un critere dans les jointures ?
 
Je prends le probleme en cours de route, donc désolé si ma proposition est inadéquoite.


---------------
http://poemes.iceteapeche.com - http://www.simuland.net
Reply

Marsh Posté le 21-03-2009 à 11:59:06    

fluminis a écrit :

Pour te faciliter la vie, est il possible de rajouter un champ dans la table des CustomFieldData ?
Tu pourrais ajouter un IS_LAST qui vaudrait 1 pour les dernieres valeurs et 0 pour toutes les valeurs historisées.
Tu n'as plus qu'a ajouter un critere dans les jointures ?
 
Je prends le probleme en cours de route, donc désolé si ma proposition est inadéquoite.


 
surtout pas! c'est une rustine qui ajoute du temps de traitement ! a bannir

Reply

Marsh Posté le 21-03-2009 à 13:56:22    

L'idée n'est pas forcément bête mais est contraire au principe de la conception d'une BD : tous ce qui peut être calculé ou redondant ne doit pas être stocké. Après, comme toute règle, il y a des exceptions, genre rajouter un champ pour stocker une valeur souvent calculée/demandée... Dans mon cas, je ne pense pas que ça se justifie.
 
Pour rappel, j'ai une solution qui marche à base de tables temporaires. Mais je n'en suis pas satisfait sur le plan intellectuel et donc je cherche à trouver une meilleure solution.
 
Akario, si tu regardes la requête de mon 2ième post, c'est ce que je fais déjà pour récupérer la valeur courante de chaque champ personnalisé. Maintenant, si on applique ça à la requête de mon dernier post, ça veut dire que je duplique la requête de mon 2ième post autant de fois que j'ai de champs persos dans ma clause where. Et c'est là mon pb. Normalement, je devrais pouvoir stocker le résultat de cette requête dans une seule table temporaire et lui donner plusieurs alias pour faire comme dans la requête de mon dernier post (elle jouerait le rôle des cfv1, cfv2). Et c'est là que ça coince : Mysql empêche de mettre plusieurs alias sur une table temporaire. Je dois donc la dupliquer dans plusieurs tables temporaires :/


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 22-03-2009 à 12:01:06    

j'ai du mal à comprendre le résultat que tu veux...
 
je vais donc exprimer ma pensée, et tu me réponds oui ou non! :-)
Le jeu de résultat que tu obtiens avec ce que je t'ai envoyé, permet d'obtenir toutes les informations que tu souhaites, versionning compris.
 
Ce jeu de résultat recupere n lignes pour un ticket  
ex (avec ton jeu de test):  je recupere les infos du ticket '0903001'
# 1                  | 2009-03-01 09:01:01  | "Site n°1"      | 1             | 1
# 2                  | 2009-03-01 09:01:01  | 5               | 2             | 1
# 6                  | 2009-03-01 11:31:01  | 1               | 2             | 1
 
j'obtiens 2 lignes :
  0903001, 1 (magasin)
  0903001, Site n°1 (site)
 
Souhaites-tu obtenir ces 2 infos sur une seule ligne?  
ex:
ticket,     magasin, site
0903001, 1          , Site n°1
 
oui ou non ?

Reply

Marsh Posté le 22-03-2009 à 20:50:26    

J'ai corrigé la ligne iD=7 de la table CustomFieldsValues, y'avait une erreur pour que le résultat fonctionne avec mon ex. Le bon résultat est le ticket 0903002 (ID=2) avec les champs persos ayant les entrées dans la table CustomFieldsValues ID=3 (valeur "Site n°3" ) et ID=5 (valeur=5).
 
Dans le résultat de ta requête,  on voit que le champ perso 1 a 2 valeurs de remontées (l'une n'étant pas la valeur courante, mais une valeur précédente). Ce n'est donc pas bon ;)


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 23-03-2009 à 08:24:45    

akario a écrit :

surtout pas! c'est une rustine qui ajoute du temps de traitement ! a bannir


 
Mouais, entre ajouter un champ qui oblige une petite manip a l'insertion des données et accelere les requetes de selection ; et une solution qui facilite l'insertion mais qui t'oblige a te casser la tete pour faire un select avec des sous requetes complexes dans tous les sens...
Apres, j'ai pas inventé ça, notre appli est en prod depuis un paquet de temps deja et c'est les dba qui nous ont fait rajouté ce champ quand la volumetrie a grossi.
Apres je suis pas dba.


---------------
http://poemes.iceteapeche.com - http://www.simuland.net
Reply

Marsh Posté le 23-03-2009 à 10:17:00    

En formation MySQL, le formateur nous a demandé au début si y'avait des dba dans la salle. Y'avait que des développeurs en l'occurrence. Il nous a expliqué que les dba, ben ils aimaient pas les formes normalisées (style 3NF...) et que quand il en avait dans la salle, les dba lui disaient de faire son speetch sur les formes normalisées vite fait et qu'ils s'en tapaient :D parce que côté perfs, les formes normalisées, c'est pas toujours tip-top...


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 23-03-2009 à 11:07:33    

rufo a écrit :

Bon, apparemment t'as pas compris mon pb ou alors, le SQL, c'est pas ton truc. Je vais donc faire un ex concret.
[...]
Donc j'ai 3 tickets dans ma table Aow. Tous les 3 ont, en plus de leurs champs dans la table Aow, des champs personnalisés. Les 2 premiers tickets (1 et 2) sont liés à 2 champs personnalisés (le 1 et le 2), le 3ième ticket est lié au champ perso n° 3. De plus, le champ personnalsié n°2 a ses changements de valeur historisés.
Dans mon moteur de recherche, je veux pouvoir lister les tickets (de la table Aow, donc)  qui ont comme valeur courante "Site%" pour le champ perso "Site" et comme valeur courante 5 pour le champ perso "Magasin". Le résultat est donc seulement le ticket n°2. Le ticket 1 ne correspondant pas car la valeur courante de son champ perso "Magasin" est 1 (bien qu'il soit passé à un moment donné à 5) et le ticket 3 n'est pas lié au champ perso "Magasin".
 
C'est plus clair, là? Tu vois donc que ta requête n'est pas bonne.


J'ai un peu de mal à comprendre les tables :
- La liaison Aow <-> CustomFields, tu la fais comment ?
J'ai l'impression qu'il manque une table de liaison entre les deux ?
 
- L'historisation dans la même table que les données courantes, c'est indispensable ?
Il n'y aurait pas moyen de faire une table CustomFieldsHisto qui contiendrait les données historisées, et de ne garder que les données courantes dans CustomFields ?
Ou au moins, de rajouter un champ "ActiveCustomField" ?
Parce que, là, tu es obligé de faire un test sur la date

Reply

Marsh Posté le 23-03-2009 à 11:12:09    

[HS]

rufo a écrit :

En formation MySQL, le formateur nous a demandé au début si y'avait des dba dans la salle. Y'avait que des développeurs en l'occurrence. Il nous a expliqué que les dba, ben ils aimaient pas les formes normalisées (style 3NF...) et que quand il en avait dans la salle, les dba lui disaient de faire son speetch sur les formes normalisées vite fait et qu'ils s'en tapaient :D parce que côté perfs, les formes normalisées, c'est pas toujours tip-top...

C'est aussi que les DBA, à chaque formation qu'ils font, ils ont droit aux formes normalisées, et au laïus comme quoi il faut normaliser à tout prix.
 
Des formateurs qui pensent à préciser que les formes normales, c'est bien mais qu'il faut savoir dénormaliser ensuite, je n'en ai pas vu beaucoup  :pfff:  
[/HS]

Reply

Marsh Posté le 23-03-2009 à 11:22:50    

La liaison entre Aow et CustomFields se fait via CustomFieldsValues (avec les champs ObjectID qui pointe sur une ID de Aow et CustomFieldID).
CustomFields est un table contenant le paramétrage des champs persos. CustomFieldsValues contient des valeurs pour des couples [champ perso, objet] (dans notre cas, l'objet est un ticket dans la table Aow).
 
Donc, pour récupérer l'ID de la valeur cournate de chaque champ de CustomFieldsValues, il "suffit" de faire cette requête :

Code :
  1. (
  2. SELECT tcfv.CustomFieldValueID, tcfv.CustomFieldValueDate, tcfv.CustomFieldValueData, tcfv.CustomFieldID, tcfv.ObjectID
  3. FROM (
  4. SELECT ObjectID, CustomFieldID, MAX( CustomFieldValueID ) AS maxCustomFieldValueID
  5. FROM CustomFieldsValues
  6. GROUP BY ObjectID, CustomFieldID
  7. ) AS curHistoCF, CustomFieldsValues tcfv
  8. WHERE curHistoCF.maxCustomFieldValueID = tcfv.CustomFieldValueID
  9. ) AS cfv


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 23-03-2009 à 11:55:45    

rufo a écrit :

La liaison entre Aow et CustomFields se fait via CustomFieldsValues (avec les champs ObjectID qui pointe sur une ID de Aow et CustomFieldID).
CustomFields est un table contenant le paramétrage des champs persos. CustomFieldsValues contient des valeurs pour des couples [champ perso, objet] (dans notre cas, l'objet est un ticket dans la table Aow).

Mais du coup, la relation Aow <-> CustomFieldsValues est du type N,N  :pfff:  
C'est - entre autres - pour ça que je propose une table d'historisation à part.
Sans l'historisation, on retrouve une relation correcte...  Et je te laisse le soin de regarder à quoi se réduirait la requête que tu proposes !  :ange:

Reply

Marsh Posté le 23-03-2009 à 13:27:48    

Oui, c'est une relation N,N, je ne vois pas où est le pb. Qu'as-tu contre les relations N,N?


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 23-03-2009 à 14:13:13    

bin juste qu'une relation N,N c'est pas trivial de selectionner dans une sous requete la ligne ou la date est la plus recente


---------------
http://poemes.iceteapeche.com - http://www.simuland.net
Reply

Marsh Posté le 23-03-2009 à 14:34:15    

fluminis a écrit :

bin juste qu'une relation N,N c'est pas trivial de selectionner dans une sous requete la ligne ou la date est la plus recente


 [:plusun]  
Le SQL est fait pour gérer des BDD Relationnelles.
A partir du moment où on a des relations N,N on abandonne le relationnel, et du coup le SQL perd de son intérêt.
La preuve, tu te retrouves, pour quelque chose qui devrait être trivial (récupérer l'ID de la valeur courante de chaque champ de CustomFieldsValues), avec des sous-requêtes et des groupements.
 
Donc, deux solutions :
1. Tu as une très bonne raison, ailleurs dans ton programme, de te retrouver avec une relation N,N
=> Il faut comparer les gains/pertes de performances, et arbitrer, en tenant compte de la complexité des solutions.
 
2. Tu n'as pas de raison particulière de conserver une relation N,N
=> Problème réglé : il faut passer à du "vrai" relationnel  :D  
 

Reply

Marsh Posté le 23-03-2009 à 16:02:18    

Bon, j'ai trouvé une méthode qui marche sans tables temporaires, par contre, c'est bête parce qu'il y a un bout de la requête qui est exécuté plusieurs fois (la partie justement qui était stockée dans les tables temporaires pour récupérer les ID des valeurs courantes des champs persos). Par contre, l'avantage, c'est que la ré-exécution de la requête est très rapide puisque mise en cache, ce qui n'est pas le cas avec la méthode des tables temporaires.

Code :
  1. SELECT a.AowID, a.AowRef, cf1.CustomFieldName AS CFN1, cfv1.CustomFieldValueData AS CFVD1, cf2.CustomFieldName AS CFN2, cfv2.CustomFieldValueData AS CFVD2 FROM
  2.     (SELECT tcfv.CustomFieldValueID, tcfv.CustomFieldValueDate, tcfv.CustomFieldValueData, tcfv.CustomFieldID, tcfv.ObjectID FROM
  3.         (SELECT ObjectID, CustomFieldID, MAX(CustomFieldValueID) AS maxCustomFieldValueID FROM CustomFieldsValues GROUP BY ObjectID, CustomFieldID) AS curHistoCF, CustomFieldsValues tcfv WHERE curHistoCF.maxCustomFieldValueID = tcfv.CustomFieldValueID) AS cfv1,
  4.     (SELECT tcfv.CustomFieldValueID, tcfv.CustomFieldValueDate, tcfv.CustomFieldValueData, tcfv.CustomFieldID, tcfv.ObjectID FROM
  5.         (SELECT ObjectID, CustomFieldID, MAX(CustomFieldValueID) AS maxCustomFieldValueID FROM CustomFieldsValues GROUP BY ObjectID, CustomFieldID) AS curHistoCF, CustomFieldsValues tcfv WHERE curHistoCF.maxCustomFieldValueID = tcfv.CustomFieldValueID) AS cfv2, CustomFields cf1, CustomFields cf2, Aow a
  6. WHERE cfv1.CustomFieldID = cf1.CustomFieldID AND cf1.CustomFieldName = "AowSite" AND cfv1.ObjectID = a.AowID
  7. AND cfv2.CustomFieldID = cf2.CustomFieldID AND cf2.CustomFieldName = "AowContactSite" AND cfv2.ObjectID = a.AowID AND cfv1.CustomFieldValueData = "44" AND cfv2.CustomFieldValueData LIKE "s%"


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed