OVH Cloud OVH Cloud

Menus déroulants et sous-requête

2 réponses
Avatar
yhautbois
J'ai crée une requête (et un formulaire associée) avec paramètre
d'entrée du type : [Choississez le fournisseur].
Quand je les exécute, la requête et le formulaire fonctionnent lorsque
je rentre le nom d'un des fournisseurs de ma table T_Fournisseurs (et
m'indiquent son adresse, son n° de tél...)

Mais, j'aimerais installer un menu déroulant qui me propose tous les
fournisseurs de ma tables T_Fournisseurs. Comment faire?

De plus, j'ai une autre table avec une clé primaire RefArt (référence
article) et un attribut RefArtFini (référence de l'article fini). A
partir de cette table (et de plusieurs autres), je veux créer une
requête me donnant l'ensemble des articles pour lesquelles les deux
références sont identiques (RefArt = RefArtFini).
Je crois savoir qu'il faut utiliser des sous-requêtes mais j'ai du mal
à avoir de bonnes infos la-dessus qui m'aideraient.

Merci d'avance.

2 réponses

Avatar
Michel Walsh
Salut,


Pour la première question, commencer par ouvrir un formulaire, avec le
combo box et, sur événement AfterUdpdate (ou depuis un bouton), là, lancer
la requête et, dans la requête, avoir FORMS!NomDuFormulaire!NomDuCombobox
comme paramètre (ou utiliser la valeur comme paramètre).

Pour la seconde question, c'est un peu flou, alors je généralise avec
une présentatio personnelle sur la "technique" des sous requêtes...


Les sous requêtes sont basées sur les "scope" (étendues) de variables,
mais à la C++


{ ' début d'étendue
int i ; ' déclare une variable entière, de nom i
int j;

i=2;
j=3;


{ ' début d'une seconde étendue, à l'intérieur de la
première
int k; ' k est visible ici, mais k n'est pas visible
dans la première étendue
' k est "locale"

k=i ; ' la variable i de la première étendue
"percole" à travers
' la nouvelle étendue, elle est visible ici
également.

int j ; ' on déclare une variable j locale, elle
"bloque" donc la variable
' j de la première étendue.

j=4;
} ' fin de l'étendue interne

imprime j; ' la valeur 3 sera imprimée, car la variable k,
ainsi que la variable "locale" j=4
' furent éliminées lors de la fin de leur
étendue.


}


On possède "un peu" la même chose en VBA:


Option Explicit
Dim i As long
Dim j As long

Public Sub Toto( )
Dim k As long
Dim j As Long
' le i "global du module" percole,
' mais le j global du module est "caché" par le j local
...
End Sub



Maintenant qu'on a saisie cette subtilité d'étendues, SQL fait de même,
mais n'utilise pas DIM, il utilise FROM. De plus, SQL utilise l'ordre de la
syntaxe C/C++:

nomDeClasse nomDeVariable ;


plutôt que l'order de la syntaxe VB/VBA:

DIM nomDeVariable AS nomDeClasse



Donc, en SQL:

SELECT quelquechose
FROM myTable AS myAlias


nous définit une variable, myAlias, à partir de la "classe" (table)
myTable, et le nom de la variable vient après le AS, alors qu'en VB/VBA, il
vient avant... mais bon, en n'en meurt pas, quand on le sait...


SELECT quelquechose
FROM myTable As myAlias
WHERE myAlias.FieldName = ( SELECT encoreqqch
FROM autreTable
AS autreAlias

....

)



Ici, les parenthèses indiquent les étendues. Donc, myAlias et autreAlias
sont connues à l'intérieur de la sous requête, autreAlias est local et
myAlias y a percollé.



SELECT quelquechose
FROM myTable As myAlias
WHERE myAlias.FieldName = ( SELECT MAX(autreAlias.encoreqqch)
FROM autreTable
AS autreAlias
WHERE
myAlias.NomDeChampDemyTable < autreAlias.NomDautreChamp
)


se lit donc, du moins, pour la sous requête, "ne conserver que les
enregistrements de autreAlias tel que la valeur de NomDautreChamp est > à
celle du cahmp NomDeChampDEmyTable dans l'enregistrement actuellement en
considération par myAlias" et "de tous les enregistrements conservés,
prendre la valeur maximale du champ encoreqqch".


En effet, les sous requêtes retournent générallement UNE seule valeur:



WHERE myAlias.FieldName = ( 22 )

a de l'allure. Si la requête interne retrournait plusieurs valeurs:

WHERE myAlias.FieldName= ( 12, 22, 11, -9 )

on aurait "de la misère", SQL nous générerait une erreur. En effet, il
faudrait utiliser IN, ou ANY:

WHERE myAlias.FieldName = ANY ( SELECT autreAlias.encoreqqch
FROM autreTable
AS autreAlias
WHERE
myAlias.NomDeChampDemyTable < autreAlias.NomDautreChamp
)


mais comme on avait utilisé SELECT MAX( ... ), la sous-requête retournait
forcément qu'une seule valeur.


Mais avant de pousser plus à fond sur les IN, ANY, ALL, EXISTS et
compagnies, terminons les étendues.

Si on n'utilise pas d'alias, dans le FROM, alors le nom de la variable
est IMPLICITEMENT généré comme étant celui de la table:



SELECT qqch
FROM table1 As a
WHERE auch = ( SELECT MAX( quovadis)
FROM table1
WHERE a.f1 = f2 )


est la même chose que

SELECT qqch
FROM table1 As a
WHERE auch = ( SELECT MAX( quovadis)
FROM table1 As b
WHERE a.f1 = b.f2 )


et qui est la même chose que


SELECT qqch
FROM table1
WHERE auch = ( SELECT MAX( quovadis)
FROM table1 As b
WHERE f1 = b.f2 )



C'est cette dernière formulation qui est généralement utilsée, parce que
c'est en écrivant table1 une second fois qu'on se rend compte qu'on doit
avoir deux variables différentes.



Passons maintenant aux IN et autres. On a vu qu'aucun universel (ANY,
ALL, IN, ... ) n'est requis si la requête retourne une seule valeur, ce qui
est le cas si :


... WHERE monChamp = (SELECT LAST( autreChamp) FROM
quepart )


car la sous requête utilise un aggrégat, ici LAST, et aucun groupe (pas de
GROUP BY).


Si la sous requête retournait plusieurs enregistrements, il faudrait
utiliser un universel:


... WHERE "ok" = ALL ( SELECT EstCeComplet FROM travaux As b
WHERE b.ContratID = ContratID )


semble insister pour retourner que les contrats ayant EstCeComplet de tous
leurs enregistrements à "ok". On a également vu un exemple de IN, très
voisin de ANY. Pour ce qui est de EXISTS, EXISTS peut être vu comme une
fonction qui retroune VRAI si il y a au moins un enregistrement dans son
argument:

.... WHERE EXISTS( SELECT * FROM maTable As b WHERE b.f1 = a.f2)


EXISTS retourne vrai si il y a au moins un enregistrement qui serait
retourné par la sous requête. Exists est souvent utilisé lorsqu'on possède
une clé composée de plusieurs champs. En effet, on ne peut pas faire:


... WHERE (champ1, champ2) IN ( SELECT champA, champB FROM .... )


mais on peut faire:


.... WHERE EXISTS( SELECT * FROM ... WHERE champ1=champA AND
champ2=champB)


Pour finir, on peut utiliser autre chose que =. Par exemple:


.... WHERE LaDate > (SELECT MAX( champDeDate) FROM .... )


Et bien sûr, la question colle:


.... WHERE f2 > ALL ( SELECT f1 FROM ... )


est proche, mais pas équivalent à

.... WHERE f2 = ( SELECT MAX(f1) FROM ... )

En effet, si f1 possède une valeur nulle, f2> NULL retroune ... NULL,
donc, il est faux que f2> tous les f1. Donc, si il y a des valeurs nulles
dans f1, les deux formulations retournent des choses différentes. Si il n'y
a pas de valeurs nulles, vous avez compris, les deux formulations sont
logiquement identiques.




Espérant être utile,
Vanderghast, Access MVP


"Yann" wrote in message
news:
J'ai crée une requête (et un formulaire associée) avec paramètre
d'entrée du type : [Choississez le fournisseur].
Quand je les exécute, la requête et le formulaire fonctionnent lorsque
je rentre le nom d'un des fournisseurs de ma table T_Fournisseurs (et
m'indiquent son adresse, son n° de tél...)

Mais, j'aimerais installer un menu déroulant qui me propose tous les
fournisseurs de ma tables T_Fournisseurs. Comment faire?

De plus, j'ai une autre table avec une clé primaire RefArt (référence
article) et un attribut RefArtFini (référence de l'article fini). A
partir de cette table (et de plusieurs autres), je veux créer une
requête me donnant l'ensemble des articles pour lesquelles les deux
références sont identiques (RefArt = RefArtFini).
Je crois savoir qu'il faut utiliser des sous-requêtes mais j'ai du mal
à avoir de bonnes infos la-dessus qui m'aideraient.

Merci d'avance.


Avatar
Michel Walsh
Errata;


Au lieu de

SELECT qqch
FROM table1
WHERE auch = ( SELECT MAX( quovadis)
FROM table1 As b
WHERE f1 = b.f2 )





il faudrait

SELECT qqch
FROM table1
WHERE auch = ( SELECT MAX( quovadis)
FROM table1 As b
WHERE table1.f1 = b.f2 )


et ainsi de même pour les autres variations. Seulement dans une contrainte
de type CHECK( ) n'est-on pas obligé de lever l'ambiguité de l'origine du
champ f1, lorsque son origine est possiblement depuis plusieurs tables.


Au lieu de




.... WHERE f2 > ALL ( SELECT f1 FROM ... )




on devrait avoir un >= pour espérer que f2=max(f1), autrement, on aurait
f2>max(f1), il va de soi.