OVH Cloud OVH Cloud

Aux spécialialistes SQL

22 réponses
Avatar
I.G.LOG
Bonjour à tous,
Je travaille avec MySQL 4.1 et Windev 12 56c ; mais ce problème est sur le
SQL:

J'ai trois tables FOURNISSEUR (1,1), COMMANDE (0,n) et LIGNECDE (0,n)

Dans LIGNECDE, j'ai un identifiant article.
Pour un article donné, je voudrai récupérer la ligne correspondant à la
dernière commande de chaque fournisseur !
J'avoue ne pas savoir comment mettre ça en place.

Merci pour votre aide

10 réponses

1 2 3
Avatar
I.G.LOG
"Firetox" a écrit dans le message de news:
4a9e449c$0$11915$
Bonjour,

non le group by fonctionne comme cela
par contre sous certain SGBD tu ne peux pas faire apparaitre une colonne
qui n'est pas dans le group by sans fonction d'aggregat et donc cette
requete sous SQLServer ne fonctionnera pas par contre en ajoutant un max
sur date tu pourrais avoir la meme chose




c'est bien ce que je pensais et c'est la raison pour laquelle le GROUP BY
est assez "aléatoire" dans sa compréhension.
Si je veux que l'appli soit portable sur d'autres SGBD, je ne peux donc pas
utiliser cette requète "spécifique MySQL" ?!
Faut-il que je rajoute un MAX quelconque (sur la date comme tu pensais) ?
Encore merci
Avatar
Firetox
Bonjour,


"I.G.LOG" a écrit dans le message de
news:4a9e4dee$0$23456$

c'est bien ce que je pensais et c'est la raison pour laquelle le GROUP BY
est assez "aléatoire" dans sa compréhension.
Si je veux que l'appli soit portable sur d'autres SGBD, je ne peux donc
pas utiliser cette requète "spécifique MySQL" ?!
Faut-il que je rajoute un MAX quelconque (sur la date comme tu pensais) ?
Encore merci



un peu plus compliqué que cela en fait sous SQLserver, car il faut aussi
pensé au prix et sous SQLServer comme il n'est pas dans le group by il va
demandé une fonction aggregat et on aura pas le bon resultat. et je pense
que sous SQLserver la solution en une seule requete est assez complexe (il
faut remonté dans une requete avec un max su la date la ligne achat concerné
pour avoir le IDLigneCommande une fois cela fait il faut faire une jointure
sur la table precedente avec le ID trouve : tu aura ainsi une seule ligne
par fournisseur, produit, et donc tu recupere le prix a ce moment la

le probleme du SQL est qu'il est actuellement tres dependant du SGBD de
destination : il ne faut pas utiliser de fonctions particuliere au SGBD il
faut faire attention au group by et aggregats qui ne fonctionnent pas tous
pareil , le procedure stockées qui ne renvoient pas les resultat de la meme
façon etc ...

le seul moyen pour avoir un code unique sur les SGBD c'est faire ce qu'a
fait PCSOFT ou que j'ai egalement fait sur SQLManagerX mais on perd en
rapidité (du coté windev cela donne HF tres performant) c'est d'utiliser des
ordres simples qui seront compatible avec tous les SGBD par exemple ta
requete ne foncionnera pas avec un client qui a decidé de reste en mySQL
3.23 (qui sait c'est son choix) et donc meme sous mySQL tu peux te retrouver
avec un code qui ne fonctionne plus

tout cela pour dire que meme si on fait la requete pour qu'elle fonctionne
sous SQLServer , elle ne fonctionnera pas ou peut être pas avec oracle ou
PostGreSQL ou encore FireBird !!

donc soit tu destine ton prog a une base est une version minimal soit tu
veux un code qui fonctionne partout et tu oubli la requete pour repassé en
parcours de requete simple avec d'autre requete simple qui vont ralentir ton
traitement

sous HFCS par exemple il y a des problemes sur les sous requetes et les
unions un peu comme la requete qu'on a fait pour le FROM mais avec des union
dedans : pour eviter cela j'ai Fait 3 requete a la place de l'union et je
simule les union lors de l'ajout dans la table (sinon ca ne marche pas) :
probleme c'est un peu plus lent (15 % de perte et sur des grosse base cela
represente 5 à 10 secondes de plus que la requete)

bon parlons de ton cas :

SELECT commande.IDFour as IDFour ,ligneCommande.IDproduit as
IDProduit,max(IDligneCommande.IDligneCommande) FROM Commande
LEFT JOIN ligneCommande ON ligneCommande.IDcommande=commande.IDCommande
GROUP By Commande.IDfournisseur ASC ,ligneCommande.IDProduit ASC

te donne normalement la derniere commande du produit chgez le fournisseur si
l'ID est un auto increment ou croissant
(j'espere que c'est le cas) ensuite on va lier cette requete avec une autre
pour avoir le resultat attendu

SELECT
TMPtable.IDFour,TMPTable.IDProduit,ligneCommande.Prix

FROM

(SELECT commande.IDFour as IDFour ,ligneCommande.IDproduit as
IDProduit,max(IDligneCommande.IDligneCommande) FROM Commande
LEFT JOIN ligneCommande ON ligneCommande.IDcommande=commande.IDCommande
GROUP By Commande.IDfournisseur ASC ,ligneCommande.IDProduit ASC
) as TMPTable

LEFT JOIN ligneCommande ON ligneCommande.IDLigneCommande =
tmpTable.IDLigneCommande

On recupere le prix (la donnée interressante) que a la fin
la sous requete doit te remonté le IDLigneCommande correspondant a la
derniere commande et on ne peut pas faire autrement a cause que sous
SQLServer que le group by impose que la colonne soit dans le group by (on ne
veut pas prix dans le group by) ou dans une fonction d'aggregat (mais on ne
veut pas max , min ou autre de prix) donc pour eviter cela il faut
identifier la ligne correspondante (par sa cle) et que le group by qui soit
fait soit correcte et ensuite on va chercher les info avec cet ID qui nous
renvoie l'info correctement

par contre si cela fonctionne sous SQLserver sous mySQLdu devrait avoir
aussi le meme resultat par contre il faudra tester sous oracle et autre SGBD
et si il n'accepte pas les sous requetes : ca marchera pas

Bon dev
@+
Avatar
I.G.LOG
merci pour cette explication.
Une conclusion s'impose: le standard SQL est encore une vue de l'esprit et -
si j'en juge ton analyse - il recèle de nombreux pièges.
Pour l'instant je vais rester "compatible MySQL 4.1" !
Encore merci
Phil
Avatar
Daniel
Bonjour,

I.G.LOG a écrit :
merci pour cette explication.
Une conclusion s'impose: le standard SQL est encore une vue de l'esprit et -
si j'en juge ton analyse - il recèle de nombreux pièges.
Pour l'instant je vais rester "compatible MySQL 4.1" !
Encore merci
Phil





La norme SQL est loin d'être une vue de l'esprit, car si elle n'existait
pas pour chaque système il faudrait apprendre un nouveau langage.

Aujourd'hui, tu vas sur MySQL, Oracle ... tu seras au minimum capable de
lire, ajouter, modifier et effacer les données d'une table. Imagine si
pour chacun de ces moteurs tu devais apprendre des syntaxes différentes.


La première norme est SQL86, sachant qu'aujourd'hui nous sommes à la
norme SQL:2008.

Ces normes impliquent le respect d'une syntaxe pour le langage, mais
également un certain nombre de fonctionnalités.

Les gros éditeurs ne sont pas les plus féroces défenseurs de ces normes
car cela leur permet d'être captif vis à vis de leurs clients.

Faire une application multi SGBD avec des requêtes multi-tables "sans
connaître la spécificité de chaque SGBD" est effectivement une vue de
l'esprit à moins de disposer d'un ORM pour la couche DAO.


--
suivre ce lien pour répondre:
http://cerbermail.com/?2KrV3YZXnn
Daniel
;-)
Avatar
I.G.LOG
>
La norme SQL est loin d'être une vue de l'esprit, car si elle n'existait
pas pour chaque système il faudrait apprendre un nouveau langage.

Aujourd'hui, tu vas sur MySQL, Oracle ... tu seras au minimum capable de
lire, ajouter, modifier et effacer les données d'une table. Imagine si
pour chacun de ces moteurs tu devais apprendre des syntaxes différentes.


La première norme est SQL86, sachant qu'aujourd'hui nous sommes à la norme
SQL:2008.

Ces normes impliquent le respect d'une syntaxe pour le langage, mais
également un certain nombre de fonctionnalités.

Les gros éditeurs ne sont pas les plus féroces défenseurs de ces normes
car cela leur permet d'être captif vis à vis de leurs clients.

Faire une application multi SGBD avec des requêtes multi-tables "sans
connaître la spécificité de chaque SGBD" est effectivement une vue de
l'esprit à moins de disposer d'un ORM pour la couche DAO.





bien sûr.
mais on aurait pu espérer qu'un besoin aussi trivial que "retourne les
dernières lignes de commande pour chaque fournisseur" suive une syntaxe
admise par "tout le monde".
Pour le reste tout à fait d'accord avec toi.
En tous cas merci à tous pour votre aide.
Avatar
ManuPavy
Bonjour,

I.G.LOG a écrit :
La norme SQL est loin d'être une vue de l'esprit, car si elle n'existait
pas pour chaque système il faudrait apprendre un nouveau langage.
... 8< 8<

Ces normes impliquent le respect d'une syntaxe pour le langage, mais
également un certain nombre de fonctionnalités.
... 8< 8<




bien sûr.
mais on aurait pu espérer qu'un besoin aussi trivial que "retourne les
dernières lignes de commande pour chaque fournisseur" suive une syntaxe
admise par "tout le monde".
Pour le reste tout à fait d'accord avec toi.
En tous cas merci à tous pour votre aide.




Le véritable mot clé qu'il manque dans les différentes propositions est
le having :
select mesChamps from mesTables
where mesConditions
group by mesChamps
having maDate = select max(maDate) from maTable where maCondition;

La solution proposée qui fonctionne sous MySQL ne le devrait pas car
MySQl "choisit" de retourner un tuple (qui nous va bien pour cet
exemple) alors qu'il est possible d'en retourner d'autres.

Cordialement,

Manu
Avatar
Firetox
Bonjour,

having maDate = select max(maDate) from maTable where maCondition;


n'est pas non plus accepté par tous les SGBD


La solution proposée qui fonctionne sous MySQL ne le devrait pas car MySQl
"choisit" de retourner un tuple (qui nous va bien pour cet exemple) alors
qu'il est possible d'en retourner d'autres.



non la table (de la sous requete) fourni les lignes dans le sens qui a faire
que le group by ne retournera que la premiere sur les valeur du group by.
j'ai des requetes qui tournent depuis 4 ans comme cela et le resultat est
bien celui attendu
mySQL ne choisi pas un tuple mais prend le premier et les lignes suivantes
ayant les memes valeurs servent a calculer s'il y a aggregat ou supprimées
sinon


Cordialement,

Manu



cordialement
Firetox
Avatar
I.G.LOG
>
Le véritable mot clé qu'il manque dans les différentes propositions est le
having :
select mesChamps from mesTables
where mesConditions
group by mesChamps
having maDate = select max(maDate) from maTable where maCondition;

La solution proposée qui fonctionne sous MySQL ne le devrait pas car MySQl
"choisit" de retourner un tuple (qui nous va bien pour cet exemple) alors
qu'il est possible d'en retourner d'autres.

Cordialement,

Manu



Bonjour,
J'ai beau chercher avec cette requete, mais je n'arrive pas à retrouver ce
que je veux, à savoir:
pour un article, toutes les lignes des dernieres commandes de chaque
fournisseur.
Avatar
Firetox
voici un exemple sous mySQL et vous allez voir comment on change les données
avec le order
ce qui montre que mySQL prend bien le premier tuple

voic la requete
select param_ID as param, code_ID as code ,libelle as lib
from parametres
order by param ASC

et le resultat
param code lib
AFF_MESSAGE_FILTRE 1 si le filtrage change pendant la generation
ALCAN 1 Mini taux alcalinite pour Ok
ALCAN 2 Maxi taux alcalinite pour Ok
CATEGORIEFOUR 1 Titre client / fournisseur
CATEGORIEFOUR 2 Titre client / fournisseur
CATEGORIEFOUR 3 Titre client / fournisseur

regarder bien le ALCAN on le code 1 (deuxieme donnée en premier

maintenant je fais cette requete
select tmp.param,tmp.code
from
(select param_ID as param, code_ID as code ,libelle as lib
from parametres
order by param ASC ) as tmp
group by tmp.param

le resultat
param code
AFF_MESSAGE_FILTRE 1
ALCAN 1
CATEGORIEFOUR 1


maintenant inversons le ORDER

dans dans la requete
select param_ID as param, code_ID as code ,libelle as lib
from parametres
order by param DESC

CATEGORIEFOUR 3 Titre client / fournisseur
CATEGORIEFOUR 2 Titre client / fournisseur
CATEGORIEFOUR 1 Titre client / fournisseur
ALCAN 2 Maxi taux alcalinite pour Ok
ALCAN 1 Mini taux alcalinite pour Ok
AFF_MESSAGE_FILTRE 1 si le filtrage change pendant la generation

on voit le ALCAN 2 en premier

et la requete

select tmp.param,tmp.code
from
(select param_ID as param, code_ID as code ,libelle as lib
from parametres
order by param DESC ) as tmp
group by tmp.param

donne

param code
AFF_MESSAGE_FILTRE 1
ALCAN 2
CATEGORIEFOUR 3

et donc c'est bien le premier tuple qui est pris c'est pour cela qu'il faut
avec le group by avoir les lignes dans l'ordre qu'on veut en sachant ce que
va faire le group by

Bon dev
@+
Avatar
ManuPavy
Firetox a écrit :
voici un exemple sous mySQL et vous allez voir comment on change les
données avec le order
ce qui montre que mySQL prend bien le premier tuple



Ce qui n'est pas incompatible au fait qu'il choisisse ce tuple, ce choix
est constant mais il ne s'agit pas d'une identification stricte dans la
requete.

voic la requete
select param_ID as param, code_ID as code ,libelle as lib
from parametres
order by param ASC

et le resultat
param code lib
AFF_MESSAGE_FILTRE 1 si le filtrage change pendant la generation
ALCAN 1 Mini taux alcalinite pour Ok
ALCAN 2 Maxi taux alcalinite pour Ok
CATEGORIEFOUR 1 Titre client / fournisseur
CATEGORIEFOUR 2 Titre client / fournisseur
CATEGORIEFOUR 3 Titre client / fournisseur

regarder bien le ALCAN on le code 1 (deuxieme donnée en premier

maintenant je fais cette requete
select tmp.param,tmp.code
from
(select param_ID as param, code_ID as code ,libelle as lib
from parametres
order by param ASC ) as tmp
group by tmp.param

le resultat
param code
AFF_MESSAGE_FILTRE 1
ALCAN 1
CATEGORIEFOUR 1


maintenant inversons le ORDER

dans dans la requete
select param_ID as param, code_ID as code ,libelle as lib
from parametres
order by param DESC

CATEGORIEFOUR 3 Titre client / fournisseur
CATEGORIEFOUR 2 Titre client / fournisseur
CATEGORIEFOUR 1 Titre client / fournisseur
ALCAN 2 Maxi taux alcalinite pour Ok
ALCAN 1 Mini taux alcalinite pour Ok
AFF_MESSAGE_FILTRE 1 si le filtrage change pendant la generation

on voit le ALCAN 2 en premier

et la requete

select tmp.param,tmp.code
from
(select param_ID as param, code_ID as code ,libelle as lib
from parametres
order by param DESC ) as tmp
group by tmp.param

donne

param code
AFF_MESSAGE_FILTRE 1
ALCAN 2
CATEGORIEFOUR 3

et donc c'est bien le premier tuple qui est pris c'est pour cela qu'il
faut avec le group by avoir les lignes dans l'ordre qu'on veut en
sachant ce que va faire le group by



Je suis d'accord, cependant, ce n'est pas "mathématiquement" juste.
MySQL est trop permissif et dans cas, ca aide.
Je suis passé de MySQL à Oracle et c'est un cas de problème rencontré
fréquemment.
Car Oracle ne permet pas que l'intégrité de la base soit dépendante de
l'implémentation physique (à raison pour ma part). Si on fait un export
plat, puis un réimport asynchrone, dans le cas de MySQL, il y aura problème.

Cependant, je conviens qu'il faille s'adapter aux techno que l'on
utilise (vers lesquels on est susceptible de passer).

Je clos le sujet, n'étant pas intervenu depuis plusieurs années sur le
forum, je ne voudrais pas troller.

Cordialement,

Manu
1 2 3