簡體   English   中英

在MySQL中需要多表查詢的幫助

[英]Need help with a multiple table query in mysql

我正在與kohana建立論壇。 我知道那里已經有不錯的,免費的論壇軟件,但這是針對家庭網站的,所以我想我會將其用作學習體驗。 我也沒有使用Kohana內置的ORM,因為我想在構建論壇的過程中進一步了解SQL。

對於我的論壇,我有4個主要表格:

  • USERS
  • TOPICS
  • POSTS
  • COMMENTS

主題表:ID(自動遞增),主題行。

USERS表:用戶名,電子郵件,姓氏和其他一些不相關的行

POSTS表:id(自動遞增),post-title,post-body,topic-id,user-id,post-date,updated-date,updated-by(其中將包含創建該人員的用戶ID)最近的評論)

注釋表:id(自動遞增),post-id,user-id和注釋


我希望在論壇主頁面上:

  • 所有主題的列表
  • 每個主題的帖子數
  • 最近更新的帖子,以及誰更新的
  • 最重要的是最近更新的主題,最有可能是“ ORDER BY Updated-date”

這是我到目前為止的查詢:

SELECT topics.id AS topic-id, 
       topics.topic, 
       post-user.id AS user-id, 
       CONCAT_WS(' ', post-user.first-name, post-user.last-name) AS name, 
       recent-post.id AS post-id, 
       post-num.post-total, 
       recent-post.title AS post-title, 
       recent-post.update_date AS updated-date, 
       recent-post.updated-by AS updated-by
  FROM topics
  JOIN (SELECT posts.topic-id,
               COUNT(*) AS post-total                 
          FROM POSTS
         WHERE posts.topic-id = topic-id 
      GROUP BY posts.topic-id) AS post-num ON topics.id = post-num.topic-id
  JOIN (SELECT posts.* 
          FROM posts 
      ORDER BY posts.update-date DESC) AS recent-post ON topics.id = recent-post.topic-id 
  JOIN  (SELECT users.*, 
                posts.user-id 
           FROM users, posts 
          WHERE posts.user-id = users.id) as post-user ON recent-post.user_id = post-user.id 
GROUP BY topics.id

該查詢幾乎可以正常工作,因為它將獲取有關具有帖子主題的所有信息。 但是它不會返回沒有任何帖子的主題

我確定查詢效率低下並且是錯誤的,因為它對posts表進行了兩個子選擇,但這是我所要指出的唯一方法。

  • 破折號不是SQL標識符中的有效字符,但是您可以改用“ _”。
  • 您不必一定要從單個SQL查詢中獲取所有內容 實際上,嘗試這樣做會使編寫代碼變得更加困難,並且有時還會使SQL優化器難以執行。
  • 在子查詢中使用ORDER BY沒有任何意義。
  • 將您的主鍵列topic_iduser_id等(而不是每個表中的“ id ”),並且您不必在選擇列表中使用別名。

這是我要解決的方法:

首先獲取每個主題的最新帖子,以及相關的用戶信息:

SELECT t.topic_id, t.topic,
  u.user_id, CONCAT_WS(' ', u.first_name, u.last_name) AS full_name,
  p.post_id, p.title, p.update_date, p.updated_by
FROM topics t
INNER JOIN 
  (posts p INNER JOIN users u ON (p.updated_by = u.user_id))
  ON (t.topic_id = p.topic_id)
LEFT OUTER JOIN posts p2
  ON (p.topic_id = p2.topic_id AND p.update_date < p2.update_date)
WHERE p2.post_id IS NULL;

然后在一個單獨的,更簡單的查詢中獲取每個主題的帖子數。

SELECT t.topic_id, COUNT(*) AS post_total
FROM topics t LEFT OUTER JOIN posts p USING (topic_id)
GROUP BY t.topic_id;

合並您的應用程序中的兩個數據集。

為了確保獲得沒有帖子的主題的結果,您將需要使用LEFT JOIN而不是JOIN進行主題和下一張表之間的第一次連接。 LEFT JOIN的意思是“即使與右表不匹配,也總是為左表中的每一行返回結果集行。”

現在要走了,但是稍后我將嘗試研究效率問題。

我將在子查詢中使用left join聯接來拉回正確的主題,然后您可以在此之外做一些其他工作以獲取一些用戶信息。

select
    s.topic_id,
    s.topic,
    u.user_id as last_updated_by_id,
    u.user_name as last_updated_by,
    s.last_post,
    s.post_count
from
    (
        select
            t.id as topic_id,
            t.topic,
            t.user_id as orig_poster,
            max(coalesce(p.post_date, t.post_date)) as last_post,
            count(*) as post_count --would be p.post_id if you don't want to count the topic
        from
            topics t
            left join posts p on
                t.id = p.topic_id
        group by
            t.topic_id,
            t.topic,
            t.user_id
    ) s
    left join posts p on
        s.topic_id = p.topic_id
        and s.last_post = p.post_date
        and s.post_count > 1 --0 if you're using p.post_id up top
    inner join users u on
        u.id = coalesce(p.user_id, s.orig_poster)
order by 
    s.last_post desc

該查詢確實引入了coalesceleft join ,這是值得研究的非常好的概念。 對於兩個參數(如此處使用的參數),您也可以在MySQL中使用ifnull ,因為它在功能上是等效的。

請記住,這是MySQL專有的(如果您需要移植此代碼)。 其它數據庫有那個(其他功能isnull在SQL Server中, nvl在Oracle中,等等,等等)。 我使用了coalesce以便可以保留所有ANSI標准的查詢。

這是一個非常復雜的查詢。 您應該注意,JOIN語句會將您的主題限制為那些發表文章的主題。 如果主題沒有帖子,則JOIN語句將其過濾掉。

請嘗試以下查詢。

SELECT * 
FROM
(
  SELECT T.Topic, 
         COUNT(AllTopicPosts.ID) NumberOfPosts, 
         MAX(IFNULL(MostRecentPost.Post-Title, '') MostRecentPostTitle,
         MAX(IFNULL(MostRecentPostUser.UserName, '') MostRecentPostUser
         MAX(IFNULL(MostRecentPost.Updated_Date, '') MostRecentPostDate
  FROM TOPICS
  LEFT JOIN POSTS AllTopicPosts ON AllTopicPosts.Topic_Id = TOPICS.ID
  LEFT JOIN 
     (
       SELECT * 
       FROM Posts P
       WHERE P.Topic_id = TOPICS.id
       ORDER BY P.Updated_Date DESC
       LIMIT 1
     ) MostRecentPost ON MostRecentPost.Topic_Id = TOPICS.ID
  LEFT JOIN USERS MostRecentPostUser ON MostRecentPostUser.ID = MostRecentPost.User_Id
  GROUP BY T.Topic
)
ORDER BY MostRecentPostDate DESC

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM