Requete / jointure sql-server

Messages postés
19
Date d'inscription
dimanche 12 octobre 2008
Statut
Membre
Dernière intervention
26 mai 2011
- - Dernière réponse : sebmafate
Messages postés
4936
Date d'inscription
lundi 17 février 2003
Statut
Modérateur
Dernière intervention
14 février 2014
- 27 mai 2011 à 09:59
Bonjour,
Je travaille sous c# avec une bdd sql server.
Je suis confronté à un problème que je n'arrive pas à résoudre.. !

Sous c# quand je fais :
String str "SELECT * FROM GITE g, RESERVATION r, CONCERNER c WHERE g.IDGITE c.IDGITE AND r.NUMRESA = c.NUMRESA AND r.NUMRESA=2";
la requête ne fonctionne pas correctement.
A votre avis, d'où vient le problème ? (sachant que le requête fonctionne parfaitement lorsqu'elle est exécutée depuis un éditeur de sql-server.

Merci de votre aide
Afficher la suite 

16 réponses

Messages postés
1540
Date d'inscription
lundi 26 mai 2003
Statut
Membre
Dernière intervention
1 août 2013
11
0
Merci
Salut,

il va nous falloir plus de précision. Si cette requête fonctionne correctement sur le client SQL Server, elle doit fonctionner dans un prog en C#. C'est donc que l'erreur doit venir d'autre chose que juste de ta requête.

Déjà, qu'entends-tu par "ne fonctionne pas correctement" ?
Elle ne te renvoie pas la même chose que depuis le client ?
Elle ne te renvoie rien du tout ?
L'exécution lève une exception/erreur ?

Es-tu déjà passe en mode debug pour en apprendre plus ?
Commenter la réponse de cs_jopop
Messages postés
19
Date d'inscription
dimanche 12 octobre 2008
Statut
Membre
Dernière intervention
26 mai 2011
0
Merci
Bonjour,
Excuse du retard, mon problème est toujours d'actualité..

Lorsque j'exécute un requete, soit elle me renvoie rien du tout, soit elle me renvoie n'importe quoi...

Par contre, je n'ai pas d'exception.

Dans l'exemple ci dessus, la requête devrait renvoyer les gites qui sont concernés par la réservation 2. Dans sql-server, ça fonctionne, mais dans mon programme c#, elle ne me renvoie rien du tout.

Voici comment je procède :
 String str "SELECT * FROM GITE g, RESERVATION r, CONCERNER c WHERE g.IDGITE c.IDGITE AND r.NUMRESA = c.NUMRESA AND r.NUMRESA=2";
           
            DataTable dt = new DataTable();

            using (SqlConnection cnDataBase = new SqlConnection("Server=XPStudio-118.\\SQLEXPRESS;Database=gites;User ID=sa;Password=******;Trusted_Connection=False;"))
            {
                cnDataBase.Open();
                SqlCommand cmTable = new SqlCommand(str, cnDataBase);
                SqlDataAdapter daTable = new SqlDataAdapter(cmTable);
                daTable.Fill(dt);
                listBox1.DataSource = dt;
                listBox1.DisplayMember = "IDGITE";

            }


Lorsque je ne fais pas mes jointures, et que j'execute une requete qui renvoie tous les gites par exemple (SELECT * from GITE), ça fonctionne parfaitement.
Commenter la réponse de poussinvert
Messages postés
4936
Date d'inscription
lundi 17 février 2003
Statut
Modérateur
Dernière intervention
14 février 2014
32
0
Merci
Bonjour,

je te conseille d'écrire ta requête en utilisant les INNER JOIN

SELECT *
FROM
GITE g,
INNER JOIN CONCERNER c ON g.IDGITE = c.IDGITE
INNER JOIN RESERVATION r ON r.NUMRESA = c.NUMRESA
WHERE r.NUMRESA=2


Sébastien FERRAND
Lead Developpeur
Microsoft Visual C# MVP 2004 - 2009
Blog Photo
Commenter la réponse de sebmafate
Messages postés
1540
Date d'inscription
lundi 26 mai 2003
Statut
Membre
Dernière intervention
1 août 2013
11
0
Merci
Re,

l'écriture de sebmafate permettra certainement d'éviter des erreurs ;)
(par contre fais gaffe il a laissé traîner une virgule, sauras-tu la retrouver :p)

Sinon j'ai du mal à imaginer une requête qui ne donne pas le même résultat dans un code C# et sur un client SQL Server. Je vois donc 2 possibilités :
- tu ne te connectes pas au même schéma depuis C# et le client SQL Server,
- l'utilisation du résultat de la requête engendre un fonctionnement imprévu.

Es-tu passé en mode debug pour vérifier que (dt.Rows == 0) juste après le daTable.Fill(dt) ?
Commenter la réponse de cs_jopop
Messages postés
4936
Date d'inscription
lundi 17 février 2003
Statut
Modérateur
Dernière intervention
14 février 2014
32
0
Merci
oui... j'ai raté la virgule :o)

SELECT *
FROM
GITE g
INNER JOIN CONCERNER c ON g.IDGITE = c.IDGITE
INNER JOIN RESERVATION r ON r.NUMRESA = c.NUMRESA
WHERE r.NUMRE

Attention, l'ancienne écriture est devenue obsolète dans SQLServer... il est donc possible qu'ADO.net pose problème.


Sébastien FERRAND
Lead Developpeur
Microsoft Visual C# MVP 2004 - 2009
Blog Photo
Commenter la réponse de sebmafate
Messages postés
1540
Date d'inscription
lundi 26 mai 2003
Statut
Membre
Dernière intervention
1 août 2013
11
0
Merci
ah, c'est bon à savoir ;)
Commenter la réponse de cs_jopop
Messages postés
19
Date d'inscription
dimanche 12 octobre 2008
Statut
Membre
Dernière intervention
26 mai 2011
0
Merci
J'ai modifié la requête pour qu'elle fonctionne dans sql-server :

SELECT g.* FROM resaGite.dbo.GITE g INNER JOIN resaGite.dbo.CONCERNER c ON g.IDGITE <gras>c.IDGITE INNER JOIN resaGite.dbo.RESERVATION r ON r.NUMRESA c.NUMRESA WHERE r.NUMRESA=2</gras>

c'est à dire qu'il fallait rajouter resaGite.dbo devant chaque tables.

Je recopie cette requête dans mon programme et... ça fonctionne !

Donc après quelques tests, j'avais fais deux erreurs. l'une était qu'il faut utiliser "INNER JOIN" pour les jointures (encore inconnu pour moi jusqu'ici), et l'autre, qu'il ne faut pas oublier la syntaxe "leNomDeLaBase.dbo.nomTable" pour chaque table.

Merci les gars en tout cas.

Et justement, ce INNER JOIN, il est utilisé uniquement avec sql-server, ou doit-il être employé même sur une base MySql par exemple ?
Commenter la réponse de poussinvert
Messages postés
1540
Date d'inscription
lundi 26 mai 2003
Statut
Membre
Dernière intervention
1 août 2013
11
0
Merci
Dans ta solution tu parles de la base "resaGite", or dans un message un peu plus haut, ta connection string pointait sur une DB nommée "gites".

Essaie quand même de refaire un test sans mettre "resaGite.dbo" devant le nom des tables, mais en mettant "resaGite" (voire "resaGite.dbo") à la place de "gites" dans ta chaîne de connexion.

Ecrire la DB devant les noms de tables à un inconvénient certain : si demain tu dois déployer un autre schéma SQL Server pour la même instance de ta plateforme, tu devras changer ton code.
Commenter la réponse de cs_jopop
Messages postés
19
Date d'inscription
dimanche 12 octobre 2008
Statut
Membre
Dernière intervention
26 mai 2011
0
Merci
Mais oui dis-donc ! Mais quel gros débile que je suis ! Depuis le début c'est ça qui m'embête !

Pour la petite histoire, la base "gites" c'est l'ancienne, et la "resaGite" c'est la nouvelle.

Donc quand on enlève les "resaGite.dbo" ça marche très bien aussi :
String str "SELECT g.* FROM GITE g INNER JOIN CONCERNER c ON g.IDGITE c.IDGITE INNER JOIN RESERVATION r ON r.NUMRESA = c.NUMRESA " +
                "WHERE r.DATERESA BETWEEN '" + dATEARRIVEEDateTimePicker.Value.ToString() + "' AND '" + dATEDEPARTDateTimePicker.Value.ToString() + "'";


Ah oui, et j'ai changé la requête : je souhaite travailler avec les dates.
Mon but final est d'extraire tous les gites qui ne sont pas réservés durant une période. Pour l'instant, cette requête m'affiche les gites qui sont réservés durant la période, mais je vais rajouter un "NOT IN" quelque par pour avoir tous les autres gites.
Je teste, je teste.......
et je suis loin d'être un pro en c# !
Commenter la réponse de poussinvert
Messages postés
1540
Date d'inscription
lundi 26 mai 2003
Statut
Membre
Dernière intervention
1 août 2013
11
0
Merci
D'habitude on préconise d'éviter les IN et NOT IN qui sont assez lourds (faudra demander à sebmafate pour plus de précision, il a l'air de bien s'y connaitre). Mais si tu optes pour cette solution, voilà la marche à suivre :
// soit la string str telle que tu l'as définie juste au-dessus
// sauf que tu remplaces SELECT g.* par SELECT g.giteID
// giteID étant la clé primaire de ta table (tu l'as peut-être appelée autrement)
string rqt = "SELECT * FROM gites gg WHERE gg.giteID NOT IN (" + str + ")";


Voir avec les experts SQL (voire SQL Server) pour une méthode plus propre et/ou plus performante ;)

NB : là il s'agit d'une question SQL, pas tellement C#
Commenter la réponse de cs_jopop
Messages postés
19
Date d'inscription
dimanche 12 octobre 2008
Statut
Membre
Dernière intervention
26 mai 2011
0
Merci
Bon, je me retrouve confronté a une autre difficulté.
Maintenant que je récupère les gites que je souhaite récupérer, je met les noms dans une listBox, comme le code l'indique :
listBox1.DataSource = dt;
listBox1.DisplayMember = "IDGITE";


Mais à chaque fois que je clique sur un item dans la liste, je souhaite mettre à jour le nom dans un textBox, mais aussi l'adresse, le code postal, la ville... tout ça dans des textBox en dessous de la fameuse liste, et je ne retrouve pas mon DataSource "dt" dans les paramètres dataBinding de chaque textBox.

Est-ce que vous comprenez ?
Si oui, comment faire ?

Merci du temps que vous passez à m'éclairer
Commenter la réponse de poussinvert
Messages postés
19
Date d'inscription
dimanche 12 octobre 2008
Statut
Membre
Dernière intervention
26 mai 2011
0
Merci
Oups, jopop je n'avais pas vu ton dernier post...
Oui d'accord, si les autres ont quelques petites choses a redire sur ma requête SQL, n'hésitez pas...
Au final, elle ressemble a ça :
String str = "SELECT g.* FROM GITE g WHERE g.IDGITE NOT IN("+
                "SELECT g.IDGITE FROM GITE g INNER JOIN CONCERNER c ON g.IDGITE c.IDGITE INNER JOIN RESERVATION r ON r.NUMRESA c.NUMRESA " +
                "WHERE r.DATEARRIVEE BETWEEN '" + dATEARRIVEEDateTimePicker.Value.ToString() + "' AND '" + dATEDEPARTDateTimePicker.Value.ToString() + "'" +
                "OR r.DATEDEPART BETWEEN '" + dATEARRIVEEDateTimePicker.Value.ToString() + "' AND '" + dATEDEPARTDateTimePicker.Value.ToString() + "'" +
                "OR ('" + dATEARRIVEEDateTimePicker.Value.ToString() + "'<r.DATEARRIVEE AND '" + dATEDEPARTDateTimePicker.Value.ToString() + "'>r.DATEDEPART)" +
                "OR ('" + dATEARRIVEEDateTimePicker.Value.ToString() + "'>r.DATEARRIVEE AND '" + dATEDEPARTDateTimePicker.Value.ToString() + "'<r.DATEDEPART)"+
                ")";

...et elle fonctionne très bien
Commenter la réponse de poussinvert
Messages postés
1540
Date d'inscription
lundi 26 mai 2003
Statut
Membre
Dernière intervention
1 août 2013
11
0
Merci
Là j'ai pas de quoi tester ton code, je réponds à la volée avec la MSDN

Pour ta ListBox je définirais plutôt le nom du gite comme DisplayMember (et l'ID dans ValueMember).

Pour ce qui est de la modification des TextBox tu passes par l'event SelectedIndexChanged de la ListBox ?
Quel y est le type du SelectedItem du sender ?
Commenter la réponse de cs_jopop
Messages postés
19
Date d'inscription
dimanche 12 octobre 2008
Statut
Membre
Dernière intervention
26 mai 2011
0
Merci
"Pour ce qui est de la modification des TextBox tu passes par l'event SelectedIndexChanged de la ListBox ?"
Alors en fait, jusqu'ici, j'avais créé un dataSource automatiquement sans toucher a une seule ligne de code.
C'est a dire que ma listeBox et mes textBox en dessous se mettaient a jour en même temps en fonction de ce que je cliquait dans ma listBox, et tout ça, automatiquement.
Mais maintenant que j'ai créé mon dataTable manuellement, je ne sais plus comment renvoyer mes textBox vers ce dataTable.

"Pour ta ListBox je définirais plutôt le nom du gite comme DisplayMember (et l'ID dans ValueMember). "
d'accord, compris.

"Quel y est le type du SelectedItem du sender ?"
Pas compris. Je ne maitrise pas encore c# a fond, donc il fait des choses tout seul et je ne sais pas comment vérifier ce que tu me demande
Commenter la réponse de poussinvert
Messages postés
1540
Date d'inscription
lundi 26 mai 2003
Statut
Membre
Dernière intervention
1 août 2013
11
0
Merci
Je connais pas trop les contrôles liés directement à des données, comment les as-tu définis ?
Peut-être peut on définir des binding "paramétrés".

Sinon je pense qu'il faudra passer par l'évènement SelectedIndexChanged.
Le cas échéant on en reparle ;) (ou tu peux directement aller sur la MSDN, tout y est)
Commenter la réponse de cs_jopop
Messages postés
4936
Date d'inscription
lundi 17 février 2003
Statut
Modérateur
Dernière intervention
14 février 2014
32
0
Merci
Pas besoin de passer par le SelectedIndexChanged...
Il suffit de binder les textbox sur le SelectedItem de ta ComboBox.

Je résume :

listBox1.DataSource = dt;
listBox1.DisplayMember = "NOMGITE";
listBox1.ValueMember = "IDGITE";

villeTextBox.DataBinding.Add("Text", listBox1.SelectedItem, "Ville");
//etc...


Quant au IN et NOT IN... rien n'empêche de les utiliser sur de petits ensemble... pour de grands ensembles de données, il faut préférer faire une jointure.



Sébastien FERRAND
Lead Developpeur
Microsoft Visual C# MVP 2004 - 2009
Blog Photo
Commenter la réponse de sebmafate