Précédent   Forum des professionnels en informatique > Logiciels > Microsoft Office > Access > Requêtes et SQL.
Requêtes et SQL. Tout ce qui concerne vos questions sur les requêtes et le SQL sous Access se trouve ici.
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 03/03/2011, 12h09   #1
Futur Membre du Club
 
Thomas M
Inscription : février 2011
Messages : 38
Détails du profil
Informations personnelles :
Nom : Thomas M

Informations forums :
Inscription : février 2011
Messages : 38
Points : 19
Points : 19
Par défaut Requête sur elle même (récursive, dépendant de l'enregistrement précédent)

Bonjour à tous,

Après quelques recherches, je n'ai toujours pas trouvé réponse à mon problème. Tout d'abord, je ne pense pas qu'il s'agisse d'une requête récursive, quoi que son fonctionnement m'y fait penser ...

J'ai une requête qui me donne des enregistrements de la sorte:

REQ:
Code :
1
2
3
4
5
6
7
 
ID_Usine	Semaine		Entrée	Conso
Usine1		"2011/09"	4000	900
Usine1		"2011/10"	0	1200
Usine1		"2011/11"	0	1150
Usine1		"2011/12"	0	1200
Usine1		"2011/13"	3500	1455
Je voudrais ainsi savoir ce qu'il me reste comme quantité à la fin de chaque semaine, selon la formule suivante : Reste = Entrée - Conso + SemainePrécédente.Reste

Je voudrais donc faire une jointure (externe) de la requête sur elle même, en rajoutant un champ SemainePrécédente, avec comme critère
Code :
ON(T1.ID_Usine = T2.ID_Usine AND T1.SemainePrécédente = T2.Semaine)
Et ensuite faire Reste=T1.Entrée-T1.Conso+T2.Reste
Mais Access n'aime pas ... "référence circulaire" bla bla bla, même avec un IIf pour mettre à zéro le reste précédent s'il est nul (pour la première semaine).

Je sais qu'il est aussi possible de trouver ce reste en faisant une somme cumulée du style:
Code :
1
2
3
4
Reste =
SOMDOM("[Entrée]", "[REQ]", "[ID_Usine]=' " & ID_Usine & " ' AND [Semaine]<' " & Semaine & " ' ")
-
SOMDOM("[Conso]", "[REQ]", "[ID_Usine]=' " & ID_Usine & " ' AND [Semaine]<' " & Semaine & " ' ")
Ce qui revient à sommer toutes les entrées et consos des semaines antérieures.

Cependant cette dernière solution est beauuuuucoup trop longue à s'executer, car je dispose de milliers d'enregistrements dans ma dernière requête, qui est déjà composée de 4 à 5 sous requêtes traitant des tables contenant plusieurs dizaines de milliers d'enregistrements ...

Merci d'avance pour votre aide
thomas.m est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/03/2011, 13h41   #2
Membre habitué
 
Inscription : janvier 2006
Messages : 99
Détails du profil
Informations personnelles :
Âge : 38

Informations forums :
Inscription : janvier 2006
Messages : 99
Points : 101
Points : 101
Bonjour,

je rebondis sur cette phrase :

Citation:
Envoyé par thomas.m Voir le message
Je voudrais ainsi savoir ce qu'il me reste comme quantité à la fin de chaque semaine, selon la formule suivante : Reste = Entrée - Conso + SemainePrécédente.Reste
Celà ne reviendrait-il pas à dire : Reste = Somme des Entrées - Somme des Consos ?

Si c'est bien le cas, la requête est ensuite facile à faire.

Cordialement,
Aegnor est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/03/2011, 13h49   #3
Futur Membre du Club
 
Thomas M
Inscription : février 2011
Messages : 38
Détails du profil
Informations personnelles :
Nom : Thomas M

Informations forums :
Inscription : février 2011
Messages : 38
Points : 19
Points : 19
Citation:
Envoyé par Aegnor Voir le message
Celà ne reviendrait-il pas à dire : Reste = Somme des Entrées - Somme des Consos ?
Citation:
Envoyé par thomas.m Voir le message
Je sais qu'il est aussi possible de trouver ce reste en faisant une somme cumulée du style:
Code :
1
2
3
4
Reste =
SOMDOM("[Entrée]", "[REQ]", "[ID_Usine]=' " & ID_Usine & " ' AND [Semaine]<' " & Semaine & " ' ")
-
SOMDOM("[Conso]", "[REQ]", "[ID_Usine]=' " & ID_Usine & " ' AND [Semaine]<' " & Semaine & " ' ")
Ce qui revient à sommer toutes les entrées et consos des semaines antérieures.
Bonjour,

C'est bien ce que je disais, mais en effet, c'est facile mais lourd ... refaire la somme pour chaque enregistrement, ce n'est pas du tout efficient, et je ne peux pas me le permettre. A moins qu'il y ait une manière plus simple et efficace de construire la requête.
thomas.m est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/03/2011, 14h45   #4
Rédacteur/Modérateur
 
Avatar de User
 
Homme Denis
Développeur informatique
Inscription : août 2004
Messages : 3 205
Détails du profil
Informations personnelles :
Nom : Homme Denis
Âge : 42
Localisation : France

Informations professionnelles :
Activité : Développeur informatique

Informations forums :
Inscription : août 2004
Messages : 3 205
Points : 5 258
Points : 5 258
Salut,

Je ne vois pas d'autre solution, sauf à essayer ceci :

Code sql :
1
2
SELECT Req.ID_Usine, Req.Entrée, Req.Conso, [Entrée]-[Conso]+nz((SELECT (sum([Entrée]) - sum([Conso])) AS rest FROM Req AS r1 WHERE r1.[ID_Usine]=Req.[ID_Usine] AND r1.[Semaine]<Req.[Semaine]),0) AS Reste
FROM Req;

A+
__________________
Merci de ne pas poster sur mon profil pour des problèmes techniques. Pour celà vous pouvez utiliser le forum ou m'envoyer un mp.

Bon développement !


Mes tutoriels et contributions sur ma page perso:
Ma page personnelle
User est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/03/2011, 15h24   #5
Futur Membre du Club
 
Thomas M
Inscription : février 2011
Messages : 38
Détails du profil
Informations personnelles :
Nom : Thomas M

Informations forums :
Inscription : février 2011
Messages : 38
Points : 19
Points : 19
Merci User, ça marche et c'est vraiment 1000 fois plus rapide que la fonction Somdom que je n'utiliserai plus jamais ...

Mais bon par contre ça met toujours 14 minutes pour m'afficher 557 restes ...
Pourtant ma requête "REQ" (qui est composée pas mal de choses déjà) ne met que 2 à 3 secondes à s'ouvrir ... (ce qui est déjà beaucoup certes)
Etant donné que je vais devoir encore effectuer beaucoup de requêtes sur cette dernière requête, il est intéressant d'enregistrer le résultat dans une table non? Tant pis la redondance d'informations?
Access ne garde t il pas en mémoire tampon les résultats des requêtes pour ne pas avoir à tout recalculer à chaque fois ?

EDIT: en sauvegardant le résultat de ma première requête "REQ" dans une table, avec une jolie clé multichamp, le calcul du reste est instantanné .. je pense que je vais dire au diable le principe de redondance des informations dans les tables. Y a t il des règles à propos de ça ?
thomas.m est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/03/2011, 15h47   #6
Rédacteur/Modérateur
 
Avatar de User
 
Homme Denis
Développeur informatique
Inscription : août 2004
Messages : 3 205
Détails du profil
Informations personnelles :
Nom : Homme Denis
Âge : 42
Localisation : France

Informations professionnelles :
Activité : Développeur informatique

Informations forums :
Inscription : août 2004
Messages : 3 205
Points : 5 258
Points : 5 258
En effet,

Il arrive dans certain cas que la création d'une table temporaire (par exemple) soit indispensable niveau performance, mais as-tu essayé de le faire en 1 seule requête sans passer par la requête intermédiaire "Req" ?

Regardes aussi si tu ne peux pas mettre des index sur certains champs pour optimiser les temps d'exécutions...

A+
__________________
Merci de ne pas poster sur mon profil pour des problèmes techniques. Pour celà vous pouvez utiliser le forum ou m'envoyer un mp.

Bon développement !


Mes tutoriels et contributions sur ma page perso:
Ma page personnelle
User est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/03/2011, 16h33   #7
Futur Membre du Club
 
Thomas M
Inscription : février 2011
Messages : 38
Détails du profil
Informations personnelles :
Nom : Thomas M

Informations forums :
Inscription : février 2011
Messages : 38
Points : 19
Points : 19
Toutes mes tables disposent de Clés Multichamps, et toutes les clés étrangères sont aussi indexées. Quasiment toutes mes relations sont faite avec l'intégrité référentielle. Tout est sensé être bien optimisé.

Effectuer la requête sans passer par "REQ" ? Ma requête "REQ" est composée de différentes jointures de requêtes, elles même composées de jointures de requêtes .. ça fait beaucoup. Je viens d'essayer, et ça met autant de temps.

Je vais donc passer par une table temporaire que je vais créer proprement en VBA, ça me parait inévitable.

Merci pour ton aide en tout cas.
thomas.m est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 08/03/2011, 12h10   #8
Futur Membre du Club
 
Thomas M
Inscription : février 2011
Messages : 38
Détails du profil
Informations personnelles :
Nom : Thomas M

Informations forums :
Inscription : février 2011
Messages : 38
Points : 19
Points : 19
Bonjour,

Dans le même thème, je me heurte à un nouveau problème ...

Je voudrais effectuer un calcul de la sorte:



Style un peu gestion des stocks (mais différent), avec chaque semaine, une livraison, une entrée qui correspond au reste de la semaine précédente, une consommation Prévision = entrée * un certain pourcentage, et ma sortie qui est l'entrée - prévision.
Dans le cas précédent, la consommation était constante et il suffisant de faire la somme des livraisons précédentes - la somme des consos précédentes.

Or dans mon cas, ce n'est pas possible comme ça. J'ai même essayé en rajoutant un champ "% cumulé" qui est le produit des % précédents, mais dès qu'une nouvelle livraison arrive, cela foire tout ( normal ! ).
Et lorsque je fais une requête du type

Code :
1
2
 
DoCmd.RunSQL "UPDATE [Ma_Table] SET Entree=SortiePrecedente(Modèle,SemainePlan)+Livraison"
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
 
Public Function SortiePrecedente(Modèle As String, Semaine As String) As Double
    Dim db As Database
    Dim rst As DAO.Recordset
    Dim strSQL As String
 
    On Error GoTo err
    Set db = CurrentDb
 
    strSQL = "SELECT [Ma_Table].Entree*[Ma_Table].% FROM [Ma_Table] " _
        & "WHERE [Ma_Table].Modèle='" & Modèle & "' AND " _
        & "[Ma_Table].SemainePlan<'" & Semaine & "';"
    Set rst = db.OpenRecordset(strSQL)
 
    If rst.EOF Then
        SortiePrecedente = 0
        Exit Function
    Else
        rst.MoveLast
        SortiePrecedente = rst.Fields(0)        
    End If
 
    rst.Close
    Set rst = Nothing
 
err:
   MsgBox (err.Description)
End Function
Mais là j'ai le droit à un joli "Erreur 94 : Mauvaise utilisation de null".
Même en faisant des tests "If(Not isnull( ... ) ) je me récupère cette erreur la ligne suivante en vouant récupérer la valeur du Fields(0).
A mon avis, cela vient du fait que je fasse la requête sur le même Champ (je veux mettre à jour le champ Entrée en fonction du champ Entrée précédent), et que la requête "UPDATE ..." ne met à jour les champs en une seule fois à la fin ...

Merci d'avance pour votre aide
thomas.m est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 08/03/2011, 13h37   #9
Futur Membre du Club
 
Thomas M
Inscription : février 2011
Messages : 38
Détails du profil
Informations personnelles :
Nom : Thomas M

Informations forums :
Inscription : février 2011
Messages : 38
Points : 19
Points : 19
Finalement j'ai trouvé. Il suffisait de refaire les étapes de calcul une par une sans chercher à repasser par la valeur du même champ précédent:

Code :
DoCmd.RunSQL "UPDATE [Ma_Table] SET Entree=SortiePrecedente(Modèle,SemainePlan)+Livraison
Et

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
 
Public Function SortiePrecedente(Modèle As String, Semaine As String) As Double
    Dim db As Database
    Dim rst As DAO.Recordset
    Dim strSQL As String
    Dim resultat As Double
 
    resultat = 0
    On Error GoTo err
    Set db = CurrentDb
    strSQL = "SELECT [MaTable].Livraison, [MaTable].%FROM [MaTable] " _
                   & "WHERE [MaTable].Modèle='" & Modèle & " ' " _
                   & "AND [MaTable].SemainePlan<'" & Semaine & "';"
    Set rst = db.OpenRecordset(strSQL)
    If rst.EOF Then
        SortiePrecedente = 0
        Exit Function
    Else
        rst.MoveFirst
        While Not rst.EOF
            resultat = (resultat + rst.Fields(0)) * (1 - rst.Fields(1)) 'calcul. toute la subtilité était là
            rst.MoveNext
        Wend
    End If
    SortiePrecedente = resultat
    rst.Close
    Set rst = Nothing     
err:
   MsgBox (err.Description)
End Function
thomas.m est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 15h27.


 
 
 
 
Partenaires

Hébergement Web