Requete imriquée a l'infini ?!

Requete imriquée a l'infini ?! - SQL/NoSQL - Programmation

Marsh Posté le 16-12-2004 à 11:53:21    

Bon voilà ca va être chaud a expliquer..
 
g une table :
 
-----------
UTILISATEUR
-----------
#login
pass
email
parent
-----------
 
 
*un utilisateur -si il a les droits, peut créer un autre utilisateur qui -si il lui donne les droits, pourra à son tour créer d'autres utilisateurs, etc...
 
*le champs "parent" renseigne le login de son créateur
 
 
j'aimerais pouvoir selectioner tous les filleuils d'un utilisateur (sur plusieurs niveaux eventuellement donc), est ce que ca serait possible une telle requête déja ?
 
un truc dans le genre :
 

Code :
  1. SELECT login fils FROM utilisateur WHERE parent='".$_SESSION["login"]."' OR fils

Reply

Marsh Posté le 16-12-2004 à 11:53:21   

Reply

Marsh Posté le 16-12-2004 à 11:55:13    

Je ne connais pas de moyen de faire ça en une seule requête...[:urd]


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 16-12-2004 à 11:58:24    

bah en plusieurs requêtes ? n'importe kelle méthode...

Reply

Marsh Posté le 16-12-2004 à 12:07:51    

Dr Raf a écrit :

bah en plusieurs requêtes ? n'importe kelle méthode...


Tu n'utilises pas un langage pour traiter tes données derrière?
Si oui tu peux le faire dans une boucle récursive....


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 16-12-2004 à 12:26:23    

PHP

Reply

Marsh Posté le 16-12-2004 à 12:48:37    

Bah alors fais une boucle...[:skeye]

Reply

Marsh Posté le 16-12-2004 à 12:50:47    

Dr Raf> heuu si j'ai bien compris ton truc, en fait, un fils d'un fils d'un fils d'un fils .. etc .. est aussi considéré comme fillieul du parent du tout premier fils ??

Reply

Marsh Posté le 16-12-2004 à 12:57:31    

Tu utilises quel SGBD ?
 
Avec Oracle c'est possible, on utilise CONNECT BY / START WITH :
http://www.info.univ-angers.fr/pub [...] lsql2.html

Reply

Marsh Posté le 17-12-2004 à 14:49:55    

Mr Mala a écrit :

Dr Raf> heuu si j'ai bien compris ton truc, en fait, un fils d'un fils d'un fils d'un fils .. etc .. est aussi considéré comme fillieul du parent du tout premier fils ??


 
heu oui.
 

Beegee a écrit :

Tu utilises quel SGBD ?
 
Avec Oracle c'est possible, on utilise CONNECT BY / START WITH :
http://www.info.univ-angers.fr/pub [...] lsql2.html


 
MySQL (free en faite...)

Reply

Marsh Posté le 17-12-2004 à 17:34:04    

Ce n'est pas possible avec une seule table, sauf si le nombre de niveaux est limité.
 
Sinon, il faut revoir le modèle avec 2 tables :
Une pour les users et une pour les ids des parents (plus niveau) d'un user. Mais ça c'est super chiant à maintenir.
 
Dans ton modèle, est-il possible de supprimer un user de la table. Si oui, que deviennent ses fils ?


---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 17-12-2004 à 17:34:04   

Reply

Marsh Posté le 03-01-2005 à 12:11:54    

oui on peut supprimer un user de la table, et l'user qui l'a supprimé hérite de ses fils.

Reply

Marsh Posté le 03-01-2005 à 14:40:42    

OK.
 
On a un problème assez similaire dans notre appli. On gère un arbre de pages et ça fait souvent beaucoup de requêtes pour pas grand chose.
 
Pour améliorer la situation, on a un champ suplémentaire dans la table qui stock le chemin sous la forme d'une chaîne de caractères.
 
Exemple :
 

user_id parent_id path
0       null      .0
1       0         .0.1
2       0         .0.2
3       1         .0.1.3
4       2         .0.2.4
5       2         .0.2.5


 
parent_id est là pour gérer l'intégrité et path pour faire des requêtes du genre :
 
select * from user where path like "%.1.%"
 
qui retourne donc la liste des enfants de 1, quel que soit sont niveau de parenté.
 
La contrepartie, c'est qu'il faut maintenir ce champ. En cas de problème, une petit routine peut le recalculer.
 
C'est VILAINPABÔ, mais c'est mieux que des requêtes en boucle...


Message édité par Mara's dad le 03-01-2005 à 14:42:44

---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 04-01-2005 à 09:36:34    

pas mal :)
merki.

Reply

Marsh Posté le 04-01-2005 à 10:35:00    

Y'a un avantage inatendu au champ path.
Si tu fais une requête triée sur path, tu te retrouve avec une liste de users triés dans le même ordre que le parcours de l'arbre des users.
 
EDIT :
 
Merde, en fait, c'est pas vrai du tout !
 
Pour que ça marche, il faut que dans le path, les IDs aient tous la même longeur...
 
Re merde, ça me fout tout mon truc en l'air :fou:


Message édité par Mara's dad le 04-01-2005 à 13:28:51

---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 04-01-2005 à 14:14:55    

Bah mets les ID sur 2 caractères (01, 02, etc.) par exemple, de toute façon en stoquant le path, tu fixes implicitement une limite au nombre d'ID, non ?

Reply

Marsh Posté le 04-01-2005 à 14:19:37    

le nombre d'id non mais la profondeur max oui

Reply

Marsh Posté le 04-01-2005 à 15:04:02    

Mara's dad a écrit :

OK.
 
On a un problème assez similaire dans notre appli. On gère un arbre de pages et ça fait souvent beaucoup de requêtes pour pas grand chose.
 
Pour améliorer la situation, on a un champ suplémentaire dans la table qui stock le chemin sous la forme d'une chaîne de caractères.
 
Exemple :
 

user_id parent_id path
0       null      .0
1       0         .0.1
2       0         .0.2
3       1         .0.1.3
4       2         .0.2.4
5       2         .0.2.5


 
parent_id est là pour gérer l'intégrité et path pour faire des requêtes du genre :
 
select * from user where path like "%.1.%"
 
qui retourne donc la liste des enfants de 1, quel que soit sont niveau de parenté.
 
La contrepartie, c'est qu'il faut maintenir ce champ. En cas de problème, une petit routine peut le recalculer.
 
C'est VILAINPABÔ, mais c'est mieux que des requêtes en boucle...


 
 
Ouais m'enfin dans ton truc, un fils n'a pas intérêt à être adopté par un autre père (ce qui peut très bien être possible), parceque pour recalculer les path, ça va faire paf le chien :D

Reply

Marsh Posté le 04-01-2005 à 17:02:33    

ya pas forcement besoin de recalculer le path mais de remplacer la partie du path correspondant à l'ancien père par le path du nouveau pour tous les fils impliqués soit qqch du genre :

Code :
  1. UPDATE users SET path=REPLACE(path, [ancien_chemin],[nouveau_chemin]) WHERE path LIKE "[ancien_chemin]%";


Message édité par dreameddeath le 04-01-2005 à 17:03:13
Reply

Marsh Posté le 04-01-2005 à 17:14:23    

Mouais.
 
M'enfin j'au aucune confiance dans ce genre de trucs...
 
Tiens, j'ai une idée pour SQL Server... Quand MySQL supportera correctement le PL/SQL ça sera aussi applicable :)

Reply

Marsh Posté le 04-01-2005 à 17:59:54    

Et hop :)
 

Code :
  1. CREATE FUNCTION getTree (@id as numeric, @level as integer) 
  2. RETURNS @tmptable table ([id] numeric, nom varchar(50), [level] integer) AS
  3. BEGIN
  4.     IF @id is null
  5.     BEGIN
  6.         insert @tmptable select null, null, null where null is not null
  7.     END
  8.     ELSE
  9.     BEGIN
  10.         declare @parent as numeric
  11.         select @parent = parent from tree where id = @id
  12.         insert @tmptable select [id], nom, @level from tree where id = @id
  13.         set @level = @level + 1
  14.         insert @tmptable select [id], nom, [level] from getTree(@parent, @level)
  15.     END
  16.     return
  17. END
  18. select * from tree
  19. id                   nom                                                parent             
  20. -------------------- -------------------------------------------------- --------------------
  21. 1                    A                                                  NULL
  22. 2                    B                                                  NULL
  23. 3                    C                                                  1
  24. 4                    D                                                  1
  25. 5                    E                                                  2
  26. 6                    F                                                  2
  27. 7                    G                                                  3
  28. 8                    H                                                  3
  29. 9                    I                                                  4
  30. 10                   J                                                  4
  31. 11                   K                                                  5
  32. 12                   L                                                  5
  33. 13                   M                                                  6
  34. 14                   N                                                  6
  35. 15                   O                                                  7
  36. 16                   P                                                  7
  37. 17                   R                                                  8
  38. 18                   S                                                  8
  39. 19                   T                                                  9
  40. 20                   U                                                  10
  41. 21                   V                                                  10
  42. 22                   W                                                  11
  43. 23                   X                                                  11
  44. 24                   Y                                                  12
  45. 25                   Z                                                  13
  46. (25 ligne(s) affectée(s))
  47. select * from getTree(25, 1) order by level desc
  48. id                   nom                                                level     
  49. -------------------- -------------------------------------------------- -----------
  50. 2                    B                                                  4
  51. 6                    F                                                  3
  52. 13                   M                                                  2
  53. 25                   Z                                                  1
  54. (4 ligne(s) affectée(s))


Message édité par Arjuna le 04-01-2005 à 18:00:20
Reply

Marsh Posté le 05-01-2005 à 12:45:42    

Mara's dad a écrit :

Y'a un avantage inatendu au champ path.
Si tu fais une requête triée sur path, tu te retrouve avec une liste de users triés dans le même ordre que le parcours de l'arbre des users.
 
EDIT :
 
Merde, en fait, c'est pas vrai du tout !
 
Pour que ça marche, il faut que dans le path, les IDs aient tous la même longeur...
 
Re merde, ça me fout tout mon truc en l'air :fou:


 
pour les trier tu fais ça :
 

usort($monTableau, 'strnatcasecmp');
reset($monTableau);


 
et hop ton tableau est vraiment trié de manière logique, c'est à dire,  
.1 < .1.1 < .1.2 < .1.10 < .1.22
et non ça :
.1 < .1.1 < .1.10 < .1.2 < .1.22

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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