Précédent   Forum des professionnels en informatique > Bases de données > Langage SQL
Langage SQL Forum d'entraide sur le langage SQL et sur les questions liées à la conception de schéma (DDL). Cours SQL
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 19/09/2011, 18h54   #1
Invité de passage
 
Homme
Intégrateur Web
Inscription : septembre 2011
Messages : 2
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Intégrateur Web
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : septembre 2011
Messages : 2
Points : 0
Points : 0
Par défaut Meilleure offre parmi plusieurs propositions

Bonjour.

Je m'excuse d'avance de vous solliciter pour un problème qui, bien que je sois persuadé qu'il est simple à résoudre, me pose bien des problèmes.
J'ai une table qui contient des propositions de contrats d'employeurs à des postulants.
j'ai une colonne id_entreprise, id_candidat, type de contrat (1 = CDI ou 2 = CDD principalement) et salaire annuel.
Les candidats peuvent recevoir plusieurs propositions. Les candidats acceptent en priorité les CDI puis le meilleur salaire proposé.
Je dois retourner, pour chaque candidat qui a reçu au moins une proposition, la meilleure.
Pourriez-vous m'aider ?
Merci.
luboman est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/09/2011, 19h27   #2
Modérateur
 
Avatar de al1_24
 
Homme Alain
Ingénieur d'études décisionnel
Inscription : mai 2002
Messages : 4 446
Détails du profil
Informations personnelles :
Nom : Homme Alain
Âge : 51
Localisation : France, Val de Marne (Île de France)

Informations professionnelles :
Activité : Ingénieur d'études décisionnel
Secteur : Conseil

Informations forums :
Inscription : mai 2002
Messages : 4 446
Points : 7 545
Points : 7 545
Quelque chose comme ça ?
Code :
1
2
3
4
5
6
7
8
9
SELECT  *
FROM    matable AS tbl
WHERE   EXISTS
        (   SELECT  1
            FROM    matable AS sel
            WHERE   tbl.id_candidat  = sel.id_candidat
            HAVING  tbl.type_contrat = MIN(sel.type_contrat)
                AND tbl.salaire      = MAX(sel.salaire)
        )
__________________
Modérateur Langage SQL
Règles du forum Langage SQL à lire par tous, N'hésitez pas à consulter les cours SQL
N'oubliez pas le bouton et pensez aux balises [code]
Si une réponse vous a aidé à résoudre votre problème, n'oubliez pas de voter pour elle en cliquant sur
al1_24 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/09/2011, 09h49   #3
Membre Expert
 
Homme Sylvain Devidal
Chef de projets Générix
Inscription : février 2010
Messages : 1 062
Détails du profil
Informations personnelles :
Nom : Homme Sylvain Devidal
Âge : 33
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Chef de projets Générix
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : février 2010
Messages : 1 062
Points : 1 515
Points : 1 515
Je suis pas sûr que ta requête marche :

Si il y a une offre en CDI (1) de 2000 €/mois et un CDD (2) de 3000 €/mois alors tu vas tenter de trouver une ligne avec min(contrat_type) = 1 et max(salaire) = 3000 alors qu'il n'existe pas de telle ligne.
StringBuilder est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/09/2011, 10h08   #4
Membre Expert
 
Homme Sylvain Devidal
Chef de projets Générix
Inscription : février 2010
Messages : 1 062
Détails du profil
Informations personnelles :
Nom : Homme Sylvain Devidal
Âge : 33
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Chef de projets Générix
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : février 2010
Messages : 1 062
Points : 1 515
Points : 1 515
Ma requête (en gras) fonctionne avec ce jeu de test sous SQL Server.

En revanche, elle doit pouvoir être améliorée avec des fonctions analytiques.

Je confirme que celle de al1_24 ne fonctionne pas.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
create table proposition
(
	id_candidat int,
	id_entreprise int,
	t_contrat int,
	salaire decimal(8,2)
);

-- Jeu de test "avec différents cas qui vont bien"
insert into proposition (id_candidat, id_entreprise, t_contrat, salaire) values (1, 1, 1, 2000);
insert into proposition (id_candidat, id_entreprise, t_contrat, salaire) values (1, 2, 2, 3000);
insert into proposition (id_candidat, id_entreprise, t_contrat, salaire) values (1, 3, 1, 2500);
insert into proposition (id_candidat, id_entreprise, t_contrat, salaire) values (2, 5, 1, 2000);
insert into proposition (id_candidat, id_entreprise, t_contrat, salaire) values (2, 4, 2, 2500);
insert into proposition (id_candidat, id_entreprise, t_contrat, salaire) values (3, 1, 2, 2500);
insert into proposition (id_candidat, id_entreprise, t_contrat, salaire) values (3, 3, 2, 3500);

select p1.id_candidat, p1.id_entreprise
from proposition p1
inner join (
	select p2.id_candidat, MAX(p2.salaire) salaire
	from proposition p2
	inner join (
		select p3.id_candidat, MIN(p3.t_contrat) t_contrat
		from proposition p3
		group by p3.id_candidat
	) t2 on t2.id_candidat = p2.id_candidat and t2.t_contrat = p2.t_contrat
	group by p2.id_candidat
) t1 on t1.id_candidat = p1.id_candidat and t1.salaire = p1.salaire;
-- Retourne les 3 donnes propositions

SELECT  *
FROM    proposition AS tbl
WHERE   EXISTS
        (   SELECT  1
            FROM    proposition AS sel
            WHERE   tbl.id_candidat  = sel.id_candidat
            HAVING  tbl.t_contrat = MIN(sel.t_contrat)
                AND tbl.salaire      = MAX(sel.salaire)
        );
-- Ne retourne qu'une seule ligne qui ne correspond pas à ce qu'on cherche

drop table proposition;

PS : Ceci dit, j'ai l'impression que ma requête a un trou dans la raquette aussi... J'arrive pas à filtrer à la fois sur le contrat et le salaire... je pense qu'il manque un join ou un truc du genre. Mais ça fait mal à la tête les sous-requêtes dès le matin
StringBuilder est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/09/2011, 10h34   #5
Modérateur
 
Avatar de CinePhil
 
Homme Philippe Leménager
Ingénieur d'études en informatique
Inscription : août 2006
Messages : 11 029
Détails du profil
Informations personnelles :
Nom : Homme Philippe Leménager
Âge : 48
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations professionnelles :
Activité : Ingénieur d'études en informatique
Secteur : Enseignement

Informations forums :
Inscription : août 2006
Messages : 11 029
Points : 18 328
Points : 18 328
Envoyer un message via MSN à CinePhil
Essaie ceci :
Code :
1
2
3
4
5
6
7
8
9
10
11
SELECT t1.id_candidat, t1.id_entreprise, t1.type_contrat, t1.salaire
FROM la_table t1
INNER JOIN
(
    SELECT id_candidat,
        MAX(((100000 / type_contrat) + salaire)) AS poids
    FROM la_table
    GROUP BY id_candidat
) t2 
    ON t2.id_candidat = t1.id_candidat
    AND t2.poids = ((100000 / t1.type_contrat) + t1.salaire)
Cette requête suppose que :
- le critère type de contrat prime sur le salaire ;
- l'identifiant du type de contrat soit un entier ;
- que ces identifiants classent dans l'ordre de préférence les différents types de contrats (1 : CDI, 2 : CDD, 3 : Freelance, 4 : Stage rémunéré, 5 : Stage non rémunéré).
__________________
Philippe Leménager. Ingénieur d'étude à l'École Nationale de Formation Agronomique.
Mon blog sur la conception des BDD, le langage SQL, le PHP avec Zend Framework...
« Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
À la maison comme au bureau, j'utilise Mandriva Linux ou Mageïa ! Soutenons l'industrie logicielle française !
Linuxiens, comptez-vous !
CinePhil est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/09/2011, 10h47   #6
Modérateur
 
Avatar de al1_24
 
Homme Alain
Ingénieur d'études décisionnel
Inscription : mai 2002
Messages : 4 446
Détails du profil
Informations personnelles :
Nom : Homme Alain
Âge : 51
Localisation : France, Val de Marne (Île de France)

Informations professionnelles :
Activité : Ingénieur d'études décisionnel
Secteur : Conseil

Informations forums :
Inscription : mai 2002
Messages : 4 446
Points : 7 545
Points : 7 545
Je me suis sans doute un peu précipité pour répondre

Deux réponses plus correctes, je pense :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SELECT  *
FROM    matable AS tbl
WHERE   EXISTS
        (   SELECT  1
            FROM    matable AS sl1
            WHERE   tbl.id_candidat  = sl1.id_candidat
            HAVING  tbl.salaire      = MAX(sl1.salaire)
            WHERE   EXISTS
                    (   SELECT  1
                        FROM    matable AS sl2
                        WHERE   sl1.id_candidat  = sl2.id_candidat
                        HAVING  sl1.type_contrat = MIN(sl2.type_contrat)
                    )
        )
;
Avec fonction analytique :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT  tbl.*
FROM    matable AS tbl
    INNER JOIN
        (   SELECT  RANK()  OVER (GROUP BY id_candidat ORDER BY type_contrat, salaire DESC) rng
                ,   type_contrat
                ,   salaire
            FROM    matable
        )   AS sel
        ON  tbl.id_candidat  = sel.id_candidat
        AND tbl.type_contrat = sel.type_contrat
        AND tbl.salaire      = sel.salaire
    WHERE   sel.rng = 1
;
Dans les deux cas, on retourne la meilleure offre (salaire le plus élevé pour le type de contrat du code le plus faible).

Les tenants d'un SQL hors norme trouveront aussi une réponse avec LIMIT.
__________________
Modérateur Langage SQL
Règles du forum Langage SQL à lire par tous, N'hésitez pas à consulter les cours SQL
N'oubliez pas le bouton et pensez aux balises [code]
Si une réponse vous a aidé à résoudre votre problème, n'oubliez pas de voter pour elle en cliquant sur
al1_24 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/09/2011, 10h50   #7
Modérateur
 
Avatar de CinePhil
 
Homme Philippe Leménager
Ingénieur d'études en informatique
Inscription : août 2006
Messages : 11 029
Détails du profil
Informations personnelles :
Nom : Homme Philippe Leménager
Âge : 48
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations professionnelles :
Activité : Ingénieur d'études en informatique
Secteur : Enseignement

Informations forums :
Inscription : août 2006
Messages : 11 029
Points : 18 328
Points : 18 328
Envoyer un message via MSN à CinePhil
Al1_24, l'utilisation du HAVING sans GROUP BY dans la première requête me choque !
Ça fonctionne ça ?

Citation:
Les tenants d'un SQL hors norme trouveront aussi une réponse avec LIMIT.
Et ma solution consistant à calculer un poids pour chaque offre et à en ressortir le MAX pour chaque candidat, elle fonctionne aussi non ?
__________________
Philippe Leménager. Ingénieur d'étude à l'École Nationale de Formation Agronomique.
Mon blog sur la conception des BDD, le langage SQL, le PHP avec Zend Framework...
« Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
À la maison comme au bureau, j'utilise Mandriva Linux ou Mageïa ! Soutenons l'industrie logicielle française !
Linuxiens, comptez-vous !
CinePhil est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/09/2011, 11h18   #8
Modérateur
 
Avatar de al1_24
 
Homme Alain
Ingénieur d'études décisionnel
Inscription : mai 2002
Messages : 4 446
Détails du profil
Informations personnelles :
Nom : Homme Alain
Âge : 51
Localisation : France, Val de Marne (Île de France)

Informations professionnelles :
Activité : Ingénieur d'études décisionnel
Secteur : Conseil

Informations forums :
Inscription : mai 2002
Messages : 4 446
Points : 7 545
Points : 7 545
Le GROUP BY id_candidat dans la première requête est implicite puisque la sélection porte à chaque fois sur un seul candidat.

Quant à ta requête, si elle est correcte sur le principe, l'usage de la constante 100000 pour pondérer le salaire en fonction du type de contrat sera peut-être à valider en fonction des éléments de salaire pris en compte (mensuel, annuel, devise, ...).
De plus, il reste à en extraire LA meilleure offre, qui est la demande exprimée par luboman
__________________
Modérateur Langage SQL
Règles du forum Langage SQL à lire par tous, N'hésitez pas à consulter les cours SQL
N'oubliez pas le bouton et pensez aux balises [code]
Si une réponse vous a aidé à résoudre votre problème, n'oubliez pas de voter pour elle en cliquant sur
al1_24 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/09/2011, 11h21   #9
Modérateur
 
Avatar de CinePhil
 
Homme Philippe Leménager
Ingénieur d'études en informatique
Inscription : août 2006
Messages : 11 029
Détails du profil
Informations personnelles :
Nom : Homme Philippe Leménager
Âge : 48
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations professionnelles :
Activité : Ingénieur d'études en informatique
Secteur : Enseignement

Informations forums :
Inscription : août 2006
Messages : 11 029
Points : 18 328
Points : 18 328
Envoyer un message via MSN à CinePhil
Citation:
Envoyé par al1_24 Voir le message
De plus, il reste à en extraire LA meilleure offre, qui est la demande exprimée par luboman
Ben il y a un MAX dans ma requête !
Citation:
Je dois retourner, pour chaque candidat qui a reçu au moins une proposition, la meilleure.
Pour chaque candidat, j'extrais le poids MAX.
__________________
Philippe Leménager. Ingénieur d'étude à l'École Nationale de Formation Agronomique.
Mon blog sur la conception des BDD, le langage SQL, le PHP avec Zend Framework...
« Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
À la maison comme au bureau, j'utilise Mandriva Linux ou Mageïa ! Soutenons l'industrie logicielle française !
Linuxiens, comptez-vous !
CinePhil est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/09/2011, 12h22   #10
Modérateur
 
Avatar de al1_24
 
Homme Alain
Ingénieur d'études décisionnel
Inscription : mai 2002
Messages : 4 446
Détails du profil
Informations personnelles :
Nom : Homme Alain
Âge : 51
Localisation : France, Val de Marne (Île de France)

Informations professionnelles :
Activité : Ingénieur d'études décisionnel
Secteur : Conseil

Informations forums :
Inscription : mai 2002
Messages : 4 446
Points : 7 545
Points : 7 545
C'est vraiment pas mon jour

En effet, tu sélectionnes LA meilleure en fonction des critères utilisés.
__________________
Modérateur Langage SQL
Règles du forum Langage SQL à lire par tous, N'hésitez pas à consulter les cours SQL
N'oubliez pas le bouton et pensez aux balises [code]
Si une réponse vous a aidé à résoudre votre problème, n'oubliez pas de voter pour elle en cliquant sur
al1_24 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/09/2011, 14h43   #11
Invité de passage
 
Homme
Intégrateur Web
Inscription : septembre 2011
Messages : 2
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Intégrateur Web
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : septembre 2011
Messages : 2
Points : 0
Points : 0
Merci tout le monde !
J'ai essayé d'appliquer la proposition de CinePhil et pour autant que je puisse en juger, j'ai bien le résultat obtenu.
Finalement, c'était assez compliqué non ? Est-ce un défaut d'élaboration de la base ?
luboman est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 03h25.


 
 
 
 
Partenaires

Hébergement Web