Sélection dans deux tables avec GROUP BY

iKelSilver - 1 août 2020 à 22:59
jacofee Messages postés 12 Date d'inscription mercredi 12 août 2020 Statut Membre Dernière intervention 16 août 2020 - 16 août 2020 à 18:07
Bonsoir,

J'ai un souci pour résoudre cette requête.
 $mRequete = "SELECT *
FROM table_personne, table_message 
WHERE Id_Personne = Compte_Message
AND      Code_Message = '".$Code."'
GROUP BY Code_Message "

Code_Message : identifiant pour une discussion entre 2 personnes.

Ce marche bien mais avec un souci.
Je voulais afficher le dernier message de la table_personne accompagné du nom, prénom, ... de la personne qui a envoyé le message.

Comment faire cela ?

J'ai pensé utiliser GROUP BY et ORDER BY qui pourraient marcher mais n'étaient pas possible.

Aidez-moi à réussir ce code.

Merci

4 réponses

GENYE50 Messages postés 3 Date d'inscription dimanche 2 août 2020 Statut Membre Dernière intervention 4 octobre 2020
3 août 2020 à 06:41
Bonjour, Là première chose à clarifier c'est la notion de 'DERNIER' message.
Par exemple, existe-t-il un champ 'DATE' ou encore un champ 'Numero de message', bref un indice qui puisse TRIER sur un historique de messages ? Ceci permettra alors de sélectionner l'enregistrement que vous considérez comme étant le 'DERNIER'.
Bref, l'analyse passe avant la technique (quelque soit le langage informatique).
0
Bonjour GENYE50,

Merci pour votre réponse.

La table_message dispose d'une clé primaire auto incrémentée donc qui peut bien jouer ce rôle de tri.

Comment puis-je l'exploiter pour obtenir ma requête ?

Merci
0
jacofee Messages postés 12 Date d'inscription mercredi 12 août 2020 Statut Membre Dernière intervention 16 août 2020 1
14 août 2020 à 21:24
Bonjour,

Votre problème est assez simple si l'on considère que la clé de la table des messages peut identifier le dernier message (vu que sa valeur est toujours croissante).
Dans le code SQL ci-dessous, je considère que la colonne clé s'appelle clé_table_message, n'ayant pas le nom de la vraie colonne.
Le principe consiste à retrouver la valeur de la clé pour le dernier message correspondant au code $code. Cette dernière est obtenue en faisant un max(clé_table_message) par la requête ci-dessous.
Ici, je n'ai mis que le code SQL pour éviter de s'encombrer avec le langage du code englobant. Bien entendu, il faudra adapter $CODE dans l'implémentation.

SELECT max(s.clé_table_message)
FROM table_message AS s
WHERE s.Code_Message = $CODE


J'ai utilisé un alias pour la table (le nom est s). Ce dernier permet d'utiliser plusieurs fois la même table dans une même requête pour lui faire jouer plusieurs rôles. Les contraintes appliquées aux alias et à la table sont indépendantes entre elles. Nous allons voir ci-dessous comment ça marche.

Une fois la valeur de la clé récupérée, il suffit de l'utiliser pour filtrer le résultat de la jointure entre table_personne et table_message. Il serait malaisé de faire deux requêtes, mais le SQL permet de combiner ces dernières :
SELECT *
FROM table_personne
	,table_message
WHERE Id_Personne = Compte_Message
	AND table_message.clé_table_message = (
		SELECT max(s.clé_table_message)
		FROM table_message AS s
		WHERE s.Code_Message = $CODE
	)

La requête retournant la valeur max de la clé pour le code $code est appelée sous-requête.

Grâce à l'alias , tout fonctionne comme si nous avions deux tables table_message. C'est le propos de cet artifice. Sans l'alias, il y aurait un conflit de noms entre la requête englobante et la sous-requête. La nomenclature des alias est libre et suit les mêmes règles que celle des objets SQL (tables, vues, procédures, fonctions...). Vous n'êtes donc pas obligé de reprendre ce nom s'il ne vous convient pas.

L'opérateur = est utilisable ici parce que MAX ne retourne qu'une seule valeur.
Suivant le dialecte SQL de votre SGBD, la définition de l'alias nécessitera ou non le mot-clé AS. A vous d'adapter le code de la requête pour que cela fonctionne.

J'espère vous avoir été utile en dépit du caractère tardif de ma réponse.

Cordialement,
0
Bonjour Jacofee,

Ça marche parfaitement comme je le veux. Mais, il y a un petit souci.
Par exemple, si je reçois les messages de Personne1, Personne2, ... La requête affiche seulement la Personne qui a envoyé le dernier message.
Hors, je désire que toutes les discussions soient aussi affichés avec leurs derniers messages.
J'ai pensé fraire GROUP BY Code_Message, ça n'a pas marché.

SELECT *
FROM table_personne
 ,table_message
WHERE Id_Personne = Compte_Message
 AND table_message.clé_table_message = (
  SELECT max(s.clé_table_message)
  FROM table_message AS s
 )
GROUP BY Code_Message DESC


Comment puis-je faire ceci ?

Merci d'avance.
0
jacofee Messages postés 12 Date d'inscription mercredi 12 août 2020 Statut Membre Dernière intervention 16 août 2020 1
16 août 2020 à 18:07
Bonjour iKelSilver,

Vous auriez dû préciser ce point dans votre premier message, vous auriez gagné du temps (tout se paye en ce bas monde hélas).
La solution est également très simple. Il suffit de créer la liste des derniers messages de chaque personne, ce qui est fait en ajoutant la contrainte suivante à la sous-requête :
WHERE s.Compte_Message = table_message.Compte_Message
.
Bien entendu, la sous-requête retournant maintenant une liste de lignes et non plus une valeur scalaire, il faut modifier la condition d'égalité avec clé_table_message qui devient un IN introduisant une liste d'éléments.
Voici le code :
SELECT *
FROM table_personne
	,table_message
WHERE Id_Personne = Compte_Message
	AND table_message.clé_table_message IN (
		SELECT max(s.clé_table_message)
		FROM table_message AS s
		WHERE s.Compte_Message = table_message.Compte_Message
		)
GROUP BY Code_Message DESC


J'en profite pour vous donner un petit conseil quant au nommage de vos colonnes. Etant donné que table_message.Compte_Message contient les références à table_personne.Id_Personne, il aurait été préférable de lui donner le même nom dans les deux tables, soit Id_Personne. Cela permet d'identifier au premier coup d'oeil les colonnes que l'on peut utiliser dans les jointures et même de mettre en oeuvre le NATURAL JOIN, ce dernier réalisant automatiquement une jointure entre deux tables avec les colonnes portant le même nom.
Un autre conseil : Utilisez la syntaxe ANSI pour les jointures, donc les clauses INNER JOIN, LEFT OUTER JOIN, RIGHT OUTER JOIN, NATURAL JOIN (INNER, LEFT et RIGHT), FULL OUTER JOIN et CROSS JOIN. Cela permet de bien séparer la logique de jointure de vos requêtes de la logique de filtrage qui se trouve, elle, dans la clause WHERE. Cela vous sera très utile. Vous trouverez une foule de documentation sur le net à ce propos.

Cordialement,
0
Rejoignez-nous