IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

MS SQL Server Discussion :

Problème avec le TOP


Sujet :

MS SQL Server

  1. #1
    Membre éclairé Avatar de MicaelFelix
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2006
    Messages
    254
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2006
    Messages : 254
    Par défaut Problème avec le TOP
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT * FROM tClient 
    LEFT JOIN
    (
    	SELECT TOP 100 PERCENT Client_ID,tTelephone.Numero, tTelephone.Poste 
    	FROM tClient_Telephone INNER JOIN tTelephone ON tClient_Telephone.Telephone_ID=tTelephone.Telephone_ID
    	ORDER BY Principal DESC
    ) vTelephone ON vTelephone.Client_ID=tClient.Client_ID
    But : récupérer un seul numéro de téléphone d'un client.
    si vous vous demandez pourquoi je fais un order by principal, c'est parce que plusieurs numéros de téléphone peuvent être principaux pour le même client (par exemple un client peut avoir deux fixes dont un principal et trois numéros de fax dont un principal), alors l'order by permet de remonter ces enregistrements dans la vue vTelephone.

    Ici j'aimerai rajouter quelque chose comme SELECT TOP 1, qui ferait extrèmement bien l'affaire... mais où le mettre?
    Car changer "SELECT TOP 100 PERCENT" par "SELECT TOP 1" ne fonctionnera pas car l'intérieur du left join ne contiendra qu'un enregistrement (j'ai testé) et donc le join ne se fera que dans le cas où on aura le premier client et le premier num de tél qui correspondent.

    Et puis je me suis dit souvent "ah oui si je fais un distinct sur le client_id il ne me remettra pas deux fois le même client dans la table finale", mais le distinct ne s'applique que sur tous les champs du select on dirait... bref cela ne m'arrange pas...

    Je suis souvent coincé avec ce genre de problème... j'ai du mal comprendre quelque chose en sql pour ce genre de sous-requête avec order by et select top

    Merci d'avance.

  2. #2
    Membre chevronné
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Mai 2007
    Messages : 356
    Par défaut
    As-tu essayé la solution suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    SELECT TOP 1 * FROM tClient 
    LEFT JOIN
    (
    	SELECT TOP 100 PERCENT Client_ID,tTelephone.Numero, tTelephone.Poste 
    	FROM tClient_Telephone INNER JOIN tTelephone ON tClient_Telephone.Telephone_ID=tTelephone.Telephone_ID
    	ORDER BY Principal DESC
    ) vTelephone ON vTelephone.Client_ID=tClient.Client_ID

  3. #3
    Membre éclairé Avatar de MicaelFelix
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2006
    Messages
    254
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2006
    Messages : 254
    Par défaut
    SELECT TOP 1 * FROM tClient ?

    Cela me retournerait seulement la première ligne correspondant au premier numéro de téléphone du premier client, moi je veux chaque client mais avec un seul numéro de téléphone maximum (et que ce numéro soit un des numéros principaux).

  4. #4
    Rédacteur
    Avatar de WOLO Laurent
    Homme Profil pro
    Architecte de base de données
    Inscrit en
    Mars 2003
    Messages
    2 741
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Congo-Brazzaville

    Informations professionnelles :
    Activité : Architecte de base de données
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2003
    Messages : 2 741
    Par défaut
    Est ce que ton model de données le permet ?
    Poste le script de création de tes tables.

    Découvrez la FAQ de MS SQL Server.
    La chance accorde ses faveurs aux esprits avertis !

  5. #5
    Membre émérite
    Avatar de shwin
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    568
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Novembre 2003
    Messages : 568
    Par défaut
    Citation Envoyé par WOLO Laurent
    Est ce que ton model de données le permet ?
    Poste le script de création de tes tables.
    Je ne crois pas que cela aye de l'importance pour le résultats qui compte avoir!

    Il faut que tu fasse un ranking sur tes # de tel en ordre d'importance apres que tu prenne le max

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    SELECT Client_ID,Numero, Poste, MAX(Ranking) FROM 
    (
    	SELECT vTelephone.Client_ID,vTelephone.Numero,  tTelephone.Poste,  CAST(RANK() OVER (PARTITION BY vTelephone.Client_ID ORDER BY Principal) AS INT) AS Ranking 
    	FROM tClient_Telephone 
    		INNER JOIN tTelephone ON tClient_Telephone.Telephone_ID=tTelephone.Telephone_ID
    ) A
    GROUP BY Client_ID,Numero,Poste

  6. #6
    Membre éclairé Avatar de MicaelFelix
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2006
    Messages
    254
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2006
    Messages : 254
    Par défaut
    Pour WOLO Laurent et ceux qui voudraient voir la structure dont je parle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    CREATE TABLE [dbo].[tClient] (
    	[Client_ID] [int] IDENTITY (1, 1) NOT NULL ,
    	[Nom] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
    	[Prenom] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
    	[Sexe] [char] (1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
    	[Dt_Naissance] [smalldatetime] NULL ,
    	[Actif] [bit] NULL ,
    	[CP12] [varchar] (12) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
    	[NAS] [varchar] (9) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
    ) ON [PRIMARY]
    GO
     
    CREATE TABLE [dbo].[tClient_Telephone] (
    	[Client_ID] [int] NOT NULL ,
    	[Telephone_ID] [int] NOT NULL 
    ) ON [PRIMARY]
    GO
     
    CREATE TABLE [dbo].[tTelephone] (
    	[Telephone_ID] [int] IDENTITY (1, 1) NOT NULL ,
    	[Telephone_Type_ID] [int] NOT NULL ,
    	[Principal] [bit] NULL ,
    	[Numero] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
    	[Poste] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
    	[Boite_Vocale] [bit] NULL ,
    	[Memo] [varchar] (250) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
    	[Communication_Type_ID] [int] NOT NULL 
    ) ON [PRIMARY]
    GO

    Pour le CAST RANK() OVER PARTITION, tu aurais des liens sur des sites qui parlent de ça? De plus SQL server me dit qu'il ne connait pas de fonction RANK().
    Je ne comprends pas trop le principe de ta solution... parce que la manière dont c'est écrit ça ne me sélectionne pas un seul enregistrement, il y a simplement un ajout de colonne, car le group by n'aura pas d'effet vu qu'un client peut avoir plusieurs téléphones donc les numéros seront différents -> le group by ne se fera pas ?

    Y'aurait-il des sites ou de la documentation pour expliquer ce genre de comportement que je désirerai effectuer :
    tClient <INNERJOIN> PREMIER(tClient_Telephone <INNERJOIN> tTelephone ORDER BY Principal DESC)

    J'ai toujours l'impression que j'utilise mal le SQL, car je ne l'utilise pas depuis beaucoup de temps et j'ai toujours l'impression qu'on doit bidouiller pour essayer d'avoir un résultat cohérent, non? (euh on va me lapider ^^ le langage sql est sensé être très performant lol)

  7. #7
    Membre Expert

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2007
    Messages
    1 216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Suisse

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Août 2007
    Messages : 1 216
    Par défaut
    Que représente exactement ton flag principal dans ta table tTelephone ?
    Si c'est bien le numéro pricinpal d'un client, et qu'on ne doit en retrouver qu'un (-> tu utilises la clause TOP), il serait logique qu'un client n'aie qu'un seul numéro de téléphone flaggué comme principal.
    Je viens de lire ton edit qui spécifie que plusieurs numéros peuvent être flaggués comme principaux pour un même client, selon le type... Donc utilisons ce filtre pour retrouver ce que tu veux...

    Ce qui rammenerai la query à :

    select Client_ID, tTelephone.Numero, tTelephone.Poste
    from tClient_Telephone
    join tTelephone on tTelephone.Telephone_ID = tClient_Telephone.Telephone_ID
    where principal = 1
    and Telephone_Type_ID = TypeDeTelephoneVoullu (fixe, fax, gsm...)


    J'ai toujours l'impression que j'utilise mal le SQL, car je ne l'utilise pas depuis beaucoup de temps et j'ai toujours l'impression qu'on doit bidouiller pour essayer d'avoir un résultat cohérent, non? (euh on va me lapider ^^ le langage sql est sensé être très performant lol)
    En général si tu connais bien la représentation business de tes données et que tu utilises bien le SQL il n'y a pas vraiment trop à bidouiller, parfois quelques petits réglages à faire, tout comme tu le ferais sur du code, quelque soit le langage...

  8. #8
    Membre éclairé Avatar de MicaelFelix
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2006
    Messages
    254
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2006
    Messages : 254
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    select Client_ID, tTelephone.Numero, tTelephone.Poste
    from tClient_Telephone
    join tTelephone on tTelephone.Telephone_ID = tClient_Telephone.Telephone_ID
    where principal = 1
    and Telephone_Type_ID = TypeDeTelephoneVoullu (fixe, fax, gsm...)
    Non car je ne veux pas limiter la requête avec un type de téléphone spécifique, je veux simplement avoir le numéro principal, quelque soit le type.

    Mais là si je vous embête avec le "Principal" c'est bien parce que ce genre de requête, si principal était à 1 une seule fois pour un téléphone d'un client, c'est facile, mais si je mettais un champ ordonné ça le serait moins.
    Par exemple si je voulais le téléphone inscrit le plus récemment (avec une date d'entrée en activité du téléphone par exemple ), c'est à dire UN seul enregistrement d'un groupe qui peut compter 1 à plusieurs enregistrements, et que ce groupe doit être ordonné (pour récupérer le premier) et que cela soit dans une requête assez longue avec des inner join, comment placer ce genre de sous-requête (bref comment récupérer le premier enregistrement, car avec le TOP ça n'a pas l'air de fonctionner comme on veut lorsqu'on est dans une requête avec des inner join de partout)?

    Mon but n'est pas d'éviter la complexité en proclamant que je garderai seulement une fois un champ "principal" dans un téléphone (qui limiterait ma requête à un type de téléphone, bref si on avait un numéro de fax c'est toujours mieux que de n'avoir aucune ligne de téléphone fixe...), j'aimerai trouver une bonne solution adaptable pour gérer ce genre de chose:

    SELECT *
    FROM tClient
    PREMIER[
    INNER JOIN tClient_Telephone [clause ON...]
    INNER JOIN tTelephone [clause ON...]
    ]

    Mais bon je pourrais penser à une autre solution, du genre placer le champ ordonné dans la table qui lie les deux tables principales, bref ensuite avoir un INNER JOIN (SELECT TOP 1 FROM tClient_Telephone ORDER BY MonChampOrdonne)vClient_Telephone [clause ON...]
    Mais dans mon cas cela ne m'arrange pas.

  9. #9
    Membre émérite
    Avatar de shwin
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    568
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Novembre 2003
    Messages : 568
    Par défaut
    Citation Envoyé par shwin Voir le message
    Il faut que tu fasse un ranking sur tes # de tel en ordre d'importance apres que tu prenne le max

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    SELECT Client_ID,Numero, Poste, MAX(Ranking) FROM 
    (
    	SELECT vTelephone.Client_ID,vTelephone.Numero,  tTelephone.Poste,  CAST(RANK() OVER (PARTITION BY vTelephone.Client_ID ORDER BY Principal) AS INT) AS Ranking 
    	FROM tClient_Telephone 
    		INNER JOIN tTelephone ON tClient_Telephone.Telephone_ID=tTelephone.Telephone_ID
    ) A
    GROUP BY Client_ID,Numero,Poste
    Le rank permet de spécifier un ordre a tes # de telephone.
    Exemple que tu as 4 telephone dont 2 principaux et 2 normaux
    Type Rank
    -------------
    Principal 4
    Principal 3
    Normal 2
    Normal 1

    Un coup que tu as un ranking, il te suffie d'utiliser le keyword MAX pour avoir celui avec le plus haut ranking (qui est le plus important)

    Pour le Keyword rank, regarde sur google

  10. #10
    Membre Expert

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2007
    Messages
    1 216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Suisse

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Août 2007
    Messages : 1 216
    Par défaut
    Par exemple si je voulais le téléphone inscrit le plus récemment
    Tu pourrais tenter ca je pense...
    On se sert du max(TT2.Telephone_ID) pour retrouver le dernier principal inséré...
    D'un autre coté, je trouve ton champ principal pas vraiment top top... Vu qu'il peut être flaggué à vrai pour plusieurs numéros d'un même groupe... A la limite un trigger on insert qui le remet à false pour le précédent numéro une fois qu'un numéro plus récent est inseré pour un client ne ferait pas de mal...

    SELECT TCT1.Client_ID, TT1.Numero, TT1.Poste
    FROM tClient_Telephone TCT1
    JOIN tTelephone TT1 ON TT1.Telephone_ID = TCT1.Telephone_ID
    AND TT1.Telephone_ID = (select max(TT2.Telephone_ID)
    from tTelephone TT2
    join tClient_Telephone TCT2 on TT1.Telephone_ID = TCT2.Telephone_ID
    where TCT2.Client_ID = TCT1.Client_ID
    and TT2.principal = 1)

Discussions similaires

  1. problème de highlight d'onglet avec la "top link bar"
    Par leon1983 dans le forum SharePoint
    Réponses: 7
    Dernier message: 10/07/2008, 16h32
  2. [HTML] problème avec margin-top
    Par bard123 dans le forum Balisage (X)HTML et validation W3C
    Réponses: 8
    Dernier message: 10/04/2008, 17h47
  3. Réponses: 4
    Dernier message: 28/06/2007, 09h49
  4. Problème avec top
    Par byloute dans le forum Debian
    Réponses: 3
    Dernier message: 05/01/2007, 15h52
  5. Problème avec select top
    Par franculo_caoulene dans le forum MS SQL Server
    Réponses: 8
    Dernier message: 10/12/2004, 15h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo