Question
J'essaie donc de créer un forum simple. Ce sera une liste de sujets dans l'ordre décroissant selon la date du sujet (s'il n'y a pas de réponse) ou la dernière réponse. Voici la structure de la base de données:
forum_topic
identifiant, nom, email, corps, date
forum_reply
id, email, corps, date, topic_id
Le forum lui-même consistera en un tableau HTML avec les en-têtes suivants:
Sujet, dernière modification, # réponses
À quoi ressemblerait la ou les requêtes pour produire une telle structure? Je pensais que cela impliquerait une jointure croisée, mais pas sûr ... Merci d'avance.
La solution
Tout d'abord, il me semble que personne n'a répondu à votre question, qui était:
À quoi ressemblerait la ou les requêtes pour produire une telle structure?
avec une structure demandée de
Sujet, Dernière modification, # réponses.
Le SQL pour produire une table de résultats avec cette structure, étant donné les structures de table que vous avez fournies, serait:
SELECT t.Id, t.Name AS Topic,
MAX(r.Date) AS LastModified,
COUNT(*) AS NumReplies
FROM Forum_Topic t
LEFT OUTER JOIN Forum_Reply r ON t.id = r.topic_id
GROUP BY t.Id, t.Name
(désolé, cela n'a été testé que sur SQL Server, car je n'ai pas accès à MySql pour le moment.)
De plus, votre structure IS est déjà normalisée. Les suggestions contraires suggèrent de faire des suppositions sur ce que vous voulez faire, par exemple, en supposant que vous êtes intéressé par le suivi des noms d'utilisateur en plus des adresses e-mail. C'est tout à fait raisonnable, mais c'est néanmoins une hypothèse. Il n’ya rien de mal, du point de vue de la normalisation, à utiliser l’adresse électronique comme identifiant unique.
Maintenant, si vous recherchez des suggestions générales sur la configuration d’une base de données, nous pouvons vous en donner beaucoup. Avant la normalisation, je commencerais par ne pas utiliser de mots clés potentiels comme noms d'objet (par exemple, ne donnez pas de noms de colonnes tels que "Nom" et "Date").
Concernant le commentaire de Matt sur la valeur NULL en l’absence de réponse: l’utilisation de la fonction COALESCE () corrigera ce problème. COALESCE () renvoie le premier argument non NULL (ou NULL si tous les arguments sont NULL). Donc, remplacez le MAX (r.Date) par MAX (COALESCE (r.Date, t.Date)).
Autres conseils
Un peu comme ceci:
select * from forum_topic
inner join forum_reply on forum_topic.id=topc_id
Cependant, n'utilisez pas select *
C'est une mauvaise pratique:)
Et je n'aime pas la façon dont vous évitez la normalisation! Ce qui signifie que je préférerais avoir:
Utilisateurs
- ID utilisateur
- Nom
Threads
- ID de fil
- Objet
- a répondu
- AskedByUserID
- Date
Réponses
- ReplyID
- ID de fil
- ID utilisateur
- répondre
- Date
Puis sélectionnez un fil de discussion comme ceci:
select ThreadID, Subject, Answered, AksedByUserID, Date from Threads
Et en sélectionnant toutes les réponses comme celle-ci
select Answer, Date, Name, Email from Threads
inner join Replies on Threads,ThreaID=Replies.ThreadID
inner join Users on AskedByUserID=UserID
where Threads.ThreadID=xxx
Maintenant, cela vient juste de l’écrire, mais vous devrez peut-être aussi ajouter un groupe.
Oui, vous devriez pouvoir l'obtenir avec une requête comme celle-ci:
SELECT
forum_topic.id,
forum_topic.name AS Topic,
MAX(forum_reply.date) AS Last_Modified,
count(*) AS Replies
FROM forum_topic
INNER JOIN forum_reply ON (forum_topic.id=forum_reply.topic_id)
GROUP BY forum_topic.id
Le " groupe par " est la magie qui nous donne une ligne par sujet, avec le MAX () et COUNT () fournit les données agrégées dont vous avez besoin.
(EDIT: j'ai oublié que le corps du premier message se trouvait dans la table des sujets, de sorte que les messages sans réponse seraient manqués par la requête ci-dessus. Filip a la bonne idée de vous suggérer de normaliser vos données. Une fois normalisé , une requête similaire à celle ci-dessus vous permettrait d'obtenir les données dont vous avez besoin).
Par "normalisé", vous voulez dire que la colonne de corps de & forum; forum_topic " devrait être supprimé et le corps du sujet devrait être la première réponse?