Mysql çoklu bir tablo sorgu ile yardıma ihtiyacı

4 Cevap php

Ben Kohana ile bir forum oluşturmaya çalışıyorum. Ben orada zaten iyi, ücretsiz bir forum yazılımıdır orada olduğunu biliyorum, ama bu bir aile site için, bu yüzden ben bir öğrenme deneyimi olarak kullanmayı düşündüm. Ben de forumda inşa sürecinde SQL hakkında daha fazla bilgi edinmek istiyorum gibi, Kohana yerleşik olan ORM kullanarak değilim.

Benim forum için ben 4 ana tablo var:

  • USERS
  • TOPICS
  • POSTS
  • COMMENTS

TOPICS tablosu: id (otomatik artırılır), konu satır.

USERS tablo: adınızı, e-posta, ad ve soyad ve diğer birkaç sigara ilişkili satırları

POSTS tablosu: id (otomatik artırılır), post-başlık, post-body, konu-id, kullanıcı kimliği, post-date, güncellenen-tarih, güncellenen-by (kullanıcı-kimliği içerecek olan En son Yorum Yaptı kişi)

COMMENTS tablosu: id (otomatik artırılır), post-id, kullanıcı kimliği ve açıklama


Ana forum sayfasında ben istiyorum:

  • tüm konuları listesi
  • Her konu için mesajların sayısı
  • son güncelleme sonrası, ve kim güncellendi
  • en son güncellenen konu "updated-date ORDER BY", üstüne büyük olasılıkla bir olmak

İşte ben bugüne kadar sorgu:

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

Bu sorgu neredeyse mesaj var konular için tüm bilgi alacak gibi çalışır. But it doesn't return the topics that don't have any posts.

Ben mesaj masaya iki alt seçimleri yapar beri sorgu verimsiz ve yanlış olduğuna emin değilim, ama ben de olduğum noktaya alabilir tek yolu buydu.

4 Cevap

Eğer mesajların olmadan konular için sonuç almak sağlamak için, LEFT JOIN yerine ilk konular ve sonraki tablo arasında birleştirme için JOIN kullanmak gerekir. "Her zaman hiçbir maçı doğru tablo ile orada bile, bir sonuç sol tablodaki her satır için satır set dönmek." SOL demektir JOIN

Gitmeliyim, ama daha sonra verimliliği konulara bakmaya çalışacağım.

  • Dash SQL tanımlayıcılar geçerli bir karakter değil, ama yerine "_" kullanabilirsiniz.
  • Mutlaka tek bir SQL sorgusu everything almak zorunda değilsiniz. Aslında, bunu yapmak için çalışıyor kod zorlaştırır, hem de bazen zor SQL iyimserlik yürütmek için yapar.
  • Bu sorguda ORDER BY kullanmak için hiçbir mantıklı.
  • Böylece (yerine "id" her tablo içinde) birincil anahtar sütunlarını topic_id, user_id, ve isim ve bunları diğer ad zorunda kalmazsınız select listesi.

Here's how I would solve this:

İlk ilişkili kullanıcı bilgileri ile konu başına en son yazı olsun:

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;

Sonra ayrı, basit sorguda konu başına mesaj sayar olsun.

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

Uygulamanızda iki veri setleri Birleştirme.

Bu çok karmaşık bir sorgu. Sen ifadeleri Mesajları sahip olanlar için konuları sınırlar JOIN dikkat etmelisiniz. Bir konu bir yazı yoksa, JOIN deyimi dışarı süzer.

Aşağıdaki sorguyu deneyin.

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

Ben doğru konuyu geri çekmek için, ve sonra kullanıcı bilgi bazılarını almak için bunun dışında küçük bir ayak işi yapabileceği bir alt sorgu içinde bir left join kullanmak istiyorum.

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

Bu sorgu, işlevsel olarak eşdeğer olduğundan, coalesce and left join , and they are very good concepts to look into. For two arguments (like used here), you can also use ifnull MySQL tanıtmak yapar.

(Bağlantı noktası için bu koda ihtiyacınız varsa) o MySQL için özel olduğunu unutmayın. Diğer veritabanları (Oracle vs vs, içinde isnull SQL Server, nvl) Bunun için diğer fonksiyonları da vardır. Tüm ANSI-ğı bu sorgu tutmak ki ben coalesce kullanılır.