OVH Cloud OVH Cloud

[MySQL] alternative à intersect

3 réponses
Avatar
Manu Pavy
Bonjour,

J'ai une requete qui me pose probleme :
Dans une appli, un utilisateur choisira parmi un liste de "Produit" les=20
gens qui utilise l'ensemble de ces produits.

sh=E9ma :

Produit : IDProduit, NomProduit
Personne : IDPersonne, NomPersonne
UtilisationProduit : IDUtilisationProduit, IDPersonne, IDProduit,=20
DateDebutU, DateDebutF.

La requete qui m'irait le mieux (en SQL99) ce serait :

select NomPersonne from Personne
left join UtilisationProduit on UtilisationProduit.IDPersonne =3D=20
Personne.IDPersonne
where UtilisationProduit.IDProduit =3D 5
intersect
select NomPersonne from Personne
left join UtilisationProduit on UtilisationProduit.IDPersonne =3D=20
Personne.IDPersonne
where UtilisationProduit.IDProduit =3D 9

par exemple. Seulement, celle ci serait construite dynamiquement (avec=20
une boucle while par exemple) et pourrait vite grandir, si l on choisi=20
de s=E9lectionner une vingtaine de produits.
C'est ce qui serait le plus simple ; or, MySQL n'impl=E9mente pas=20
INTERSECT, j ai donc essayer de g=E9n=E9rer ma requete en me limitant =E0=
deux=20
produits:
select NomPersonne, count(*) cmpt from Personne
left join UtilisationProduit on UtilisationProduit.IDPersonne=3D=20
Personne.IDPersonne
where UtilisationProduit.IDProduit in (5,9)
group by UtilisationProduit.IDPersonne
having cmpt =3D 2

Cependant, je n'ai pas de contrainte d'unicit=E9 sur le couple=20
(IDPersonne, IDProduit) de la table Utilisation car une utilisation est=20
dat=E9e et qu'une personne peut donc tres bien avoir une double=20
utilisation en cours.

Je me suis alors pench=E9 sur les jointures, mais le probl=E8me est que, =

m=EAme si j arrive =E0 trouver une solution par ce biais, je pense que la=
=20
programmation pour trois, quatre, voire vingt produits sera d=E9licates.
C'est pourquoi, j aimerais savoir si quelqu un apercois une autre=20
solution (autre que changer de SGBD qui m est impos=E9) par exemple par l=
a=20
cr=E9ation de table temporaire.

Merci,

Manu

3 réponses

Avatar
Manu Pavy

Je me suis alors penché sur les jointures, mais le problème est que ,
même si j arrive à trouver une solution par ce biais, je pense que la
programmation pour trois, quatre, voire vingt produits sera délicates .



Ca y est, je l'ai :

select * from Personne
left join UtilisationProduit u on u.IDPersonne = Personne.IDPersonne
left join UtilisationProduit u2 on u2.IDPersonne = Personne.IDPersonne
where u.IDProduit = 11 and u2.IDProduit = 1

Finalement, ca n'est pas si compliqué : on rajoute une jointure
"u".i.".IDPersonne"
et une condition
"u".i.".IDProduit"

Reste la question de "rapidité", est ce optimisé ?

J espère ne pas "polluer" le group avec mes questions-réponses ; en m eme
temps, ca peut servir par la suite.

Manu
Avatar
Fred BROUARD - SQLpro
SELECT NomPersonne
FROM Personne P
LEFT OUTER JOIN UtilisationProduit U
ON U.IDPersonne = P.IDPersonne
WHERE U.IDProduit = 5
AND NomPersonne IN (SELECT NomPersonne
FROM Personne P
LEFT OUTER JOIN UtilisationProduit U
ON U.IDPersonne = P.IDPersonne = 9)

A +

Manu Pavy a écrit:
Bonjour,

J'ai une requete qui me pose probleme :
Dans une appli, un utilisateur choisira parmi un liste de "Produit" les
gens qui utilise l'ensemble de ces produits.

shéma :

Produit : IDProduit, NomProduit
Personne : IDPersonne, NomPersonne
UtilisationProduit : IDUtilisationProduit, IDPersonne, IDProduit,
DateDebutU, DateDebutF.

La requete qui m'irait le mieux (en SQL99) ce serait :

select NomPersonne from Personne
left join UtilisationProduit on UtilisationProduit.IDPersonne =
Personne.IDPersonne
where UtilisationProduit.IDProduit = 5
intersect
select NomPersonne from Personne
left join UtilisationProduit on UtilisationProduit.IDPersonne =
Personne.IDPersonne
where UtilisationProduit.IDProduit = 9

par exemple. Seulement, celle ci serait construite dynamiquement (avec
une boucle while par exemple) et pourrait vite grandir, si l on choisi
de sélectionner une vingtaine de produits.
C'est ce qui serait le plus simple ; or, MySQL n'implémente pas
INTERSECT, j ai donc essayer de générer ma requete en me limitant à deux
produits:
select NomPersonne, count(*) cmpt from Personne
left join UtilisationProduit on UtilisationProduit.IDPersonne=
Personne.IDPersonne
where UtilisationProduit.IDProduit in (5,9)
group by UtilisationProduit.IDPersonne
having cmpt = 2

Cependant, je n'ai pas de contrainte d'unicité sur le couple
(IDPersonne, IDProduit) de la table Utilisation car une utilisation est
datée et qu'une personne peut donc tres bien avoir une double
utilisation en cours.

Je me suis alors penché sur les jointures, mais le problème est que,
même si j arrive à trouver une solution par ce biais, je pense que la
programmation pour trois, quatre, voire vingt produits sera délicates.
C'est pourquoi, j aimerais savoir si quelqu un apercois une autre
solution (autre que changer de SGBD qui m est imposé) par exemple par la
création de table temporaire.

Merci,

Manu




--
Frédéric BROUARD, MVP SQL Server. Expert SQL / spécialiste Delphi, web
Livre SQL - col. Référence : http://sqlpro.developpez.com/bookSQL.html
Le site du SQL, pour débutants et pros : http://sqlpro.developpez.com
************************ www.datasapiens.com *************************
Avatar
Manu Pavy
Fred BROUARD - SQLpro a fait part de :

SELECT NomPersonne
FROM Personne P
LEFT OUTER JOIN UtilisationProduit U
ON U.IDPersonne = P.IDPersonne
WHERE U.IDProduit = 5
AND NomPersonne IN (SELECT NomPersonne
FROM Personne P
LEFT OUTER JOIN UtilisationProduit U
ON U.IDPersonne = P.IDPersonne = 9)




Merci,
Mais je me limite à ma solution qui est bonne (et plus "automatisable")
car celle-ci passe par un select imbriqué (non disponible dans ma
version) ; mais je note le "= 9" dans le predicat de jointure.
Est ce pour l optimisation ?

Manu