Précédent   Forum des professionnels en informatique > Autres langages > Autres langages > Basic > PureBasic
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 12/07/2011, 15h37   #1
Invité régulier
 
Inscription : mars 2007
Messages : 24
Détails du profil
Informations forums :
Inscription : mars 2007
Messages : 24
Points : 5
Points : 5
Par défaut Problème de requêtes SQL imbriquées

Bonjour à tous,

Je bloque sur un aspect concernant le parcours du résultat des requêtes SQL en Purebasic. Voilà mon problème :

Je souhaite alimenter une treeview avec toutes les catégories existantes dans ma base de données, sachant que certaines catégories sont parentes d'autres. Voici le schéma simplifié de ma table "CATEGORIES" :

id_categorie INT PRIMARY KEY
nom_categorie VARCHAR(100)
parent_cat_id INT (clé étrangère)

Et les données dans la table :
Code :
1
2
3
4
 
id_categorie    |    nom_categorie                    | parent_cat_id
          1         |    Bureautique                        |           0
          2         |    Word                                 |           1
Dans mon code, une première requete sélectionne toutes les catégories sans catégorie enfant, puis pour chacune, une seconde requête recherche si elle posède des catégories enfant et doit les afficher. Or, ça ne fonctionne pas car purebasic semble s'emmeler les pinceaux et considère apparemment qu'il n ya qu'un seul résultat de requete (enfin à ce qu'il me semble).

Voici mon code :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
If DatabaseQuery(1, "SELECT * FROM categories WHERE parent_categorie_id=0;" ) 
    While NextDatabaseRow(1) > 0 
        ; on récupère l'id de la catégorie
        id_cat.l = GetDatabaseLong(1,0)
        AddGadgetItem(#Lst_Categories, id_cat, GetDatabaseString(1,1) + " - " + GetDatabaseString(1,2),0, 0)
        ; on regarde s'il y a des catégories enfant
        If DatabaseQuery(1, "SELECT * FROM categories WHERE parent_categorie_id=id_cat;" ) 
            While NextDatabaseRow(1) > 0 
                AddGadgetItem(#Lst_Categories, id_cat, GetDatabaseString(1,1) + " - " + GetDatabaseString(1,2),0, 1)
            Wend
 
        EndIf
            Wend 
    FinishDatabaseQuery(1) 
    CloseDatabase(1) 
Else
    MessageRequester("ERREUR","Selection impossible"+Chr(13)+DatabaseError(),#PB_MessageRequester_Ok)
EndIf
Qu'est ce que je fais mal ?

Merci de votre aide et à bientôt.

Amicalement,

Jean-Marc
leroimarco est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 12/07/2011, 20h34   #2
Responsable Purebasic
 
Avatar de comtois
 
Inscription : avril 2003
Messages : 810
Détails du profil
Informations forums :
Inscription : avril 2003
Messages : 810
Points : 1 856
Points : 1 856
En effet, tu ne peux pas imbriquer tes requêtes ainsi.
J'ai déjà vu des réponses à ce problème, certains proposent d'utiliser une liste chainée intermédiaire pour stocker les résultats de la première requête.

D'autres proposent de changer le numéro de la base pour chaque requête imbriquée.

Par exemple :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
Procedure.l ParseDatabase(name.s,user.s,password.s)
 
  ; Parse Databases
 
  dbDB = OpenDatabase(#PB_Any,name,user,password)
 
  If dbDB
 
    If DatabaseQuery(dbDB,"SHOW DATABASES")
 
      *conn.DATABASE = NewList2(DATABASE)
 
      While NextDatabaseRow(dbDB)
 
        *db.DATABASE = AddElement2(*conn)
        *db\name = GetDatabaseString(dbDB,0)
        *db\tables = NewList2(TABLE)
 
        ; Parse Tables
 
        dbTable = OpenDatabase(#PB_Any,name,user,password)
 
        If dbTable
 
          If DatabaseQuery(dbTable,"SHOW TABLES FROM " + *db\name)
 
            While NextDatabaseRow(dbTable)
 
              *table.TABLE = AddElement2(*db\tables)
              *table\name = GetDatabaseString(dbTable,0)
              *table\fields = NewList2(FIELD)
 
              ; Parse Fields
 
              dbField = OpenDatabase(#PB_Any,name,user,password)
 
              If dbField
 
                If DatabaseQuery(dbField,"DESCRIBE " + *db\name + "." + *table\name)
 
                  While NextDatabaseRow(dbField)
 
                    *field.FIELD = AddElement2(*table\fields)
                    *field\name  = GetDatabaseString(dbField,0)
                    *field\type  = GetDatabaseString(dbField,1)
                    *field\null  = GetDatabaseString(dbField,2)
                    *field\key   = GetDatabaseString(dbField,3)
                    *field\def   = GetDatabaseString(dbField,4)
                    *field\extra = GetDatabaseString(dbField,5)
 
                  Wend
 
                EndIf
 
                CloseDatabase(dbField)
 
              EndIf
 
            Wend
 
          EndIf
 
          CloseDatabase(dbTable)
 
        EndIf
 
      Wend
 
    EndIf
 
    CloseDatabase(dbDB)
 
  EndIf
 
  ProcedureReturn *conn
 
EndProcedure
Ce qui dans ton cas donnerait :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
If DatabaseQuery(1, "SELECT * FROM categories WHERE parent_categorie_id=0;" ) 
  While NextDatabaseRow(1) > 0 
    ; on récupère l'id de la catégorie
    id_cat.l = GetDatabaseLong(1,0)
    AddGadgetItem(#Lst_Categories, id_cat, GetDatabaseString(1,1) + " - " + GetDatabaseString(1,2),0, 0)
    ; on regarde s'il y a des catégories enfant
    Enfant = OpenDatabase(#PB_Any, xxxxxxxxxxxxxx)
 
    If DatabaseQuery(enfant, "SELECT * FROM categories WHERE parent_categorie_id=id_cat;" ) 
      While NextDatabaseRow(Enfant) > 0 
        AddGadgetItem(#Lst_Categories, id_cat, GetDatabaseString(Enfant,1) + " - " + GetDatabaseString(Enfant,2),0, 1)
      Wend
        FinishDatabaseQuery(Enfant) 
        CloseDatabase(Enfant) 
    EndIf
  Wend 
  FinishDatabaseQuery(1) 
  CloseDatabase(1) 
Else
  MessageRequester("ERREUR","Selection impossible"+Chr(13)+DatabaseError(),#PB_MessageRequester_Ok)
EndIf
__________________
Vous souhaitez participer à la rubrique PureBasic (tutoriels, FAQ, sources) ? Contactez-moi par MP.
comtois est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 12/07/2011, 21h30   #3
Invité régulier
 
Inscription : mars 2007
Messages : 24
Détails du profil
Informations forums :
Inscription : mars 2007
Messages : 24
Points : 5
Points : 5
Par défaut Solutions

Bonjour Comtois et merci de ta contribution.

Tes 2 solutions répondent effectivement à mon problème. je vais étudier les listes chainées, solution qui me semble la plus "propre". Cependant les 2 sont intéressantes et étendent fortement mes compétences en Purebasic.

Même si je n'ai pas encore testé tout ça, je mets le post en "résolu"

Encore merci de ta réactivité, bonne soirée et bon code à toi

Amicalement,

Jean-Marc
leroimarco est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/07/2011, 17h44   #4
Invité régulier
 
Inscription : mars 2007
Messages : 24
Détails du profil
Informations forums :
Inscription : mars 2007
Messages : 24
Points : 5
Points : 5
Re bonjour à tous,

Finalement j'ai retiré la mention "RESOLU" car je galère encore un peu avec mon histoire de catégories et sous catégories.

En fait, je ne sais pas à l'avance le niveau d'imbrication des catégories (ce sont les utilisateurs qui décident), j'ai essayé de faire ça :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
id_item_liste = 0
parent_id.l = 0
Procedure ParcoursCategories(parent_id)
 
    If DatabaseQuery(1, "SELECT * FROM categories WHERE parent_categorie_id=" + Str(parent_id) + ";" ) 
        While NextDatabaseRow(1) > 0 
 
            AddGadgetItem(#Lst_Categories, id_item_liste, GetDatabaseString(1,1) + " - " + GetDatabaseString(1,2),0, 0)
 
            id_item_liste = id_item_liste + 1
            ; on récupère l'id de la catégorie
            id_cat.l = GetDatabaseQuad(1,0)
            parent_id = id_cat
            ParcoursCategories(parent_id)
        Wend
    EndIf      
EndProcedure
J'ai créé une procédure récursive, et tout naïf que je suis, je pensais que ça le ferais. Mais ce n'est pas du tout le cas, toujours le même problème je pense d'imbrication des requêtes SQL.

Je vais essayer de modifier le code pour inclure si c'est possible les instructions de connexion à la BDD à chaque appel de la procédure mais sans conviction. Si vous voyez un début de solution à ce problème, vous êtes les bienvenus

Merci d'avance.

Amicalement,

Jean-Marc
leroimarco est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/07/2011, 18h22   #5
Invité régulier
 
Inscription : mars 2007
Messages : 24
Détails du profil
Informations forums :
Inscription : mars 2007
Messages : 24
Points : 5
Points : 5
Petite modification avec des variables globales pour voir, mais sans succès :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 
Global id_item_liste = 0
Global parent_id.l = 0
Global db.l = 1
Global id_cat.l
Global niveau.l = 0
Global dbDB = 1
Procedure ParcoursCategories2(parent_id)
        OpenDatabase(dbDB, *****)
        If DatabaseQuery(dbDB, "SELECT * FROM categories WHERE parent_categorie_id=" + Str(parent_id) + ";" ) 
            While NextDatabaseRow(dbDB) > 0 
 
                AddGadgetItem(#Lst_Categories, id_item_liste, GetDatabaseString(1,1) + " - " + GetDatabaseString(1,2),0, niveau)
                Debug parent_id
                id_item_liste = id_item_liste + 1
                ; on récupère l'id de la catégorie
                id_cat.l = GetDatabaseQuad(1,0)
                parent_id = id_cat
                dbDB= dbDB+ 1
                niveau = niveau +1
                ParcoursCategories2(parent_id)
            Wend
        EndIf      
 
 
EndProcedure
ParcoursCategories2(parent_id)
leroimarco est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/07/2011, 18h35   #6
Invité régulier
 
Inscription : mars 2007
Messages : 24
Détails du profil
Informations forums :
Inscription : mars 2007
Messages : 24
Points : 5
Points : 5
Par défaut Je progresse...

Dernières modifications du code, y a du mieux mais c'est pas encore ça. En fait, il me parcours la première cat, descends dans les sous cat, et ainsi de suite mais il ne "remonte" pas dans l'arborescence...

Voici le code

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 
Global id_item_liste = 0
Global parent_id.l = 0
Global db.l = 1
Global id_cat.l
Global niveau.l = 0
Global dbDB = 1
Procedure ParcoursCategories2(parent_id)
        dbDB = OpenDatabase(#PB_Any, "***")
        If DatabaseQuery(dbDB, "SELECT * FROM categories WHERE parent_categorie_id=" + Str(parent_id) + ";" ) 
            While NextDatabaseRow(dbDB) > 0 
 
                AddGadgetItem(#Lst_Categories, id_item_liste, GetDatabaseString(dbDB,1) + " - " + GetDatabaseString(dbDB,2),0, niveau)
 
                id_item_liste = id_item_liste + 1
                ; on récupère l'id de la catégorie
                id_cat.l = GetDatabaseQuad(dbDB,0)
                parent_id = id_cat
                dbDB= dbDB + 1
                niveau = niveau +1
                ParcoursCategories2(parent_id)
            Wend
        EndIf      
EndProcedure
ParcoursCategories2(parent_id)
leroimarco est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/07/2011, 22h05   #7
Responsable Purebasic
 
Avatar de comtois
 
Inscription : avril 2003
Messages : 810
Détails du profil
Informations forums :
Inscription : avril 2003
Messages : 810
Points : 1 856
Points : 1 856
Je ne connais rien aux bases de données, j'ai juste fait cet essai pour découvrir Sqlite.

Mais à tout hasard, tu es sûr d'avoir défini ta base correctement ? J'ai l'impression que tu as tout mélangé dans une seule table ?

Si je comprends bien ton problème, tes catégories pourraient être contenues dans une table , les sous catégories dans une autre table ? j'ignore le niveau d'imbrication que peuvent avoir tes catégories ?

Pour valider l'organisation de ta base de données, tu peux peut-être aussi demander conseil sur le forum base de données ? Je ne connais pas ton parcours, ce conseil est sans doute inutile
__________________
Vous souhaitez participer à la rubrique PureBasic (tutoriels, FAQ, sources) ? Contactez-moi par MP.
comtois est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/07/2011, 22h39   #8
Invité régulier
 
Inscription : mars 2007
Messages : 24
Détails du profil
Informations forums :
Inscription : mars 2007
Messages : 24
Points : 5
Points : 5
Bonsoir Comtois et merci de te pencher à nouveau sur mon problème.


Citation:
Envoyé par comtois Voir le message
Mais à tout hasard, tu es sûr d'avoir défini ta base correctement ? J'ai l'impression que tu as tout mélangé dans une seule table ?
Oui, pas de souci de ce côté là, ma modélisation est bonne

Citation:
Envoyé par comtois Voir le message
Si je comprends bien ton problème, tes catégories pourraient être contenues dans une table , les sous catégories dans une autre table ? j'ignore le niveau d'imbrication que peuvent avoir tes catégories ?
Non, tout est dans la même table, comme le montre mon schéma du premier post, c'est dans le but justement de pouvoir obtenir un niveau d'imbrication catégories/sous catégories élevé.

Je pense que le problème doit venir très certainement de mon code, je dois m'y prendre de travers

Ce n'est pas dramatique, je vais adapter pour me limiter à 3 niveaux d'imbrication ce qui n'est déjà pas si mal et correspond à mon usage (par exemple : Formations informatiques -> Bureautique -> Excel )

Encore merci de ton aide et bon 14 juillet !

Amicalement,

Jean-Marc
leroimarco est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 14/07/2011, 00h14   #9
Responsable Purebasic
 
Avatar de comtois
 
Inscription : avril 2003
Messages : 810
Détails du profil
Informations forums :
Inscription : avril 2003
Messages : 810
Points : 1 856
Points : 1 856
Je lirai cet article plus tard, mais j'ai l'impression qu'il répond à ton problème ?

http://sqlpro.developpez.com/cours/s...te-recursives/

Sinon le feu d'artifice était joli ! comme l'année dernière quoi.

Bon au lit, demain y'a le défilé !
__________________
Vous souhaitez participer à la rubrique PureBasic (tutoriels, FAQ, sources) ? Contactez-moi par MP.
comtois est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 14/07/2011, 11h57   #10
Invité régulier
 
Inscription : mars 2007
Messages : 24
Détails du profil
Informations forums :
Inscription : mars 2007
Messages : 24
Points : 5
Points : 5
Citation:
Envoyé par comtois Voir le message
Je lirai cet article plus tard, mais j'ai l'impression qu'il répond à ton problème ?

http://sqlpro.developpez.com/cours/s...te-recursives/

Sinon le feu d'artifice était joli ! comme l'année dernière quoi.

Bon au lit, demain y'a le défilé !
Pas de feu d'artifice pour moi mais un BON GROS début de solution grâce à ton lien, Comtois !

Effectivement, ça correspond bien à ce que je souhaite faire. Je vais étudier ça en détail

Merci beaucoup à toi !

Bons dévs !

Amicalement,

Jean-Marc
leroimarco est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 06h36.


 
 
 
 
Partenaires

Hébergement Web