Optimiser deux sous-requête EXISTS OR NOT EXISTS

a marqué ce sujet comme résolu.

Coucou,

J'ai deux tables :

  • users ( user_id, user_firstname, user_lastname… )
  • cotisations_users ( cotiu_id_user, cotiu_start, cotiu_end )

Chaque entrée de cotisation_users est donc une durée car les cotisations sont valables un an, à partir de la date du paiement. Mais certains utilisateurs ne paient pas de cotisation, donc il n'y a pas toujours d'entrée cotisation_users correspondant à un user_id.

Il me faut donc une requête pour lister tous les utilisateurs qui n'ont pas encore d'entrée dans cotisations_users, mais également ceux dont la date de fin de la cotisation est dépassée.

J'ai fait cette requête qui fonctionne :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
SELECT  user_id, user_firstname, user_lastname
FROM    users
WHERE   NOT EXISTS
        (
                SELECT  cotiu_id_user
                FROM    cotisations_users
                WHERE   cotiu_id_user = user_id
        )
        OR EXISTS
        (
                SELECT  cotiu_id_user, cotiu_end
                FROM    cotisations_users
                WHERE   cotiu_id_user = user_id AND cotiu_end < CURRENT_DATE()
        )

Mais je trouve ça relativement affreux puisque ça me fait potentiellement deux sous-requêtes… J'imagine qu'il y a moyen de faire mieux, mais comme je ne suis pas du tout expert en SQL, je poste ici ^^

Merci :)

+0 -0

J'aurai plutot opté pour une jointure externe. ça donnerait quelque chose de la sorte.

1
2
3
4
5
SELECT user_id, user_firstname, user_lastname
FROM users
FULL OUTER JOIN cotisations_users
ON cotisations_users.cotiu_id_user=users.user_id
WHERE (cotisations_users.cotiu_id_user IS NULL) OR (cotisations_users.cotiu_end < CURRENT_DATE());

Pour ma par je garderai la table cotisations_users pour l'historique, mais j'aurai mis l'informations utile directment dans users avec un champ cotiu_end, de cette manière on a pas besoin du tout de jointure, juste de vérifier que la date n'est pas dépassée ou null.

Lorsque l'utilisateur cotise on ajoute une entrée dans cotisations_users et on met à jour la table users.

+0 -0

J'aurai plutot opté pour une jointure externe. ça donnerait quelque chose de la sorte.

1
2
3
4
5
SELECT user_id, user_firstname, user_lastname
FROM users
FULL OUTER JOIN cotisations_users
ON cotisations_users.cotiu_id_user=users.user_id
WHERE (cotisations_users.cotiu_id_user IS NULL) OR (cotisations_users.cotiu_end < CURRENT_DATE());

firm1

Ca semble en effet beaucoup plus propre, mais j'ai omis de le mentionner, c'est pour MySQL, donc ce type de jointure n'est pas supporté :( . Y'a des alternatives avec UNION, mais là je patauge :-°

Pour ma par je garderai la table cotisations_users pour l'historique, mais j'aurai mis l'informations utile directment dans users avec un champ cotiu_end, de cette manière on a pas besoin du tout de jointure, juste de vérifier que la date n'est pas dépassée ou null.

Lorsque l'utilisateur cotise on ajoute une entrée dans cotisations_users et on met à jour la table users.

La source

Je n'aime pas trop l'idée de dupliquer des données. Mais c'est vrai que c'est plus simple…

J'aurai plutot opté pour une jointure externe. ça donnerait quelque chose de la sorte.

1
2
3
4
5
SELECT user_id, user_firstname, user_lastname
FROM users
FULL OUTER JOIN cotisations_users
ON cotisations_users.cotiu_id_user=users.user_id
WHERE (cotisations_users.cotiu_id_user IS NULL) OR (cotisations_users.cotiu_end < CURRENT_DATE());

firm1

Ca semble en effet beaucoup plus propre, mais j'ai omis de le mentionner, c'est pour MySQL, donc ce type de jointure n'est pas supporté :( . Y'a des alternatives avec UNION, mais là je patauge :-°

Thunderseb

Arf, MySQL c'est vraiment pas un SGBD correct :-°

Mais on devrait s'en sortir avec une simple jointure à droite. ça donnerait quelque chose comme ça :

1
2
3
4
SELECT user_id, user_firstname, user_lastname
FROM cotisations_users AS c
RIGHT JOIN users AS u ON u.user_id = c.cotiu_id_user
WHERE (c.cotiu_id_user IS NULL) OR (c.cotiu_end < CURRENT_DATE());

Sur la base de ton premier essai, c'est pas ça que tu veux ?

1
2
3
4
5
6
7
8
SELECT  user_id, user_firstname, user_lastname
FROM    users
WHERE   NOT EXISTS
        (
                SELECT  cotiu_id_user
                FROM    cotisations_users
                WHERE   cotiu_id_user = user_id AND cotiu_end >= CURRENT_DATE()
        )
+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte