MySQL:加入很多表

时间:2013-04-15 18:35:12

标签: mysql sql join

我在MySQL数据库中有这些表用于简单的大学图书馆应用程序(由于显而易见的原因,我将它们简化了一点):

SELECT * FROM language;
╔═════════════╦══════════╗
║ language_id ║ language ║
╠═════════════╬══════════╣
║          11 ║  English ║
║          12 ║  Russian ║
║          13 ║   German ║
╚═════════════╩══════════╝

SELECT * FROM subject;
╔════════════╦═════════════╗
║ subject_id ║   subject   ║
╠════════════╬═════════════╣
║         21 ║ Mathematics ║
║         22 ║     History ║
║         23 ║   Chemistry ║
║         24 ║     Physics ║
╚════════════╩═════════════╝

SELECT publisher_id, publisher FROM publisher;
╔══════════════╦═══════════════╗
║ publisher_id ║   publisher   ║
╠══════════════╬═══════════════╣
║           31 ║ Berkley Books ║
║           32 ║       Penguin ║
╚══════════════╩═══════════════╝

SELECT author_id, first_name, last_name FROM author;
╔═══════════╦════════════╦═══════════╗
║ author_id ║ first_name ║ last_name ║
╠═══════════╬════════════╬═══════════╣
║        41 ║        Joe ║    Schmoe ║
║        42 ║       John ║     Smith ║
╚═══════════╩════════════╩═══════════╝

SELECT book_id, title, language_id, subject_id, publisher_id FROM book;
╔═════════╦═══════╦═════════════╦════════════╦══════════════╗
║ book_id ║ title ║ language_id ║ subject_id ║ publisher_id ║
╠═════════╬═══════╬═════════════╬════════════╬══════════════╣
║       1 ║     A ║          11 ║         22 ║           31 ║
║       2 ║     B ║          13 ║         24 ║           32 ║
╚═════════╩═══════╩═════════════╩════════════╩══════════════╝

SELECT book_id, author_id FROM book_author;
╔═════════╦════════════╗
║ book_id ║ author_id  ║
╠═════════╬════════════╣
║       1 ║         41 ║
║       1 ║         42 ║
║       2 ║         41 ║
╚═════════╩════════════╝

SELECT book_copy_id, book_id FROM book_copy;
╔══════════════╦═════════╗
║ book_copy_id ║ book_id ║
╠══════════════╬═════════╣
║            1 ║       1 ║
║            2 ║       1 ║
║            3 ║       1 ║
║            4 ║       2 ║
║            5 ║       2 ║
╚══════════════╩═════════╝

我有一个看起来像这样的查询(我为了以防万一而向你展示):

SELECT b.book_id,
       b.title,
       GROUP_CONCAT(CONCAT_WS(' ', a.last_name,
                                   a.first_name)
                              ORDER BY a.last_name
                              SEPARATOR ', ') AS authors,
       l.language,
       s.subject,
       p.publisher
FROM   book AS b
       LEFT JOIN book_author AS ba
              ON b.book_id = ba.book_id
       LEFT JOIN author AS a
              ON ba.author_id = a.author_id
       LEFT JOIN language AS l
              ON b.language_id = l.language_id
       LEFT JOIN subject AS s
              ON b.subject_id = s.subject_id
       LEFT JOIN publisher AS p
              ON b.publisher_id = p.publisher_id
GROUP BY b.title ASC;

╔═════════╦═══════╦════════════════════════╦══════════╦═════════╦═══════════════╗
║ book_id ║ title ║         authors        ║ language ║ subject ║   publisher   ║
╠═════════╬═══════╬════════════════════════╬══════════╬═════════╬═══════════════╣
║       1 ║     A ║ Joe Schmoe, John Smith ║  English ║ History ║ Berkley Books ║
║       2 ║     B ║             John Smith ║   German ║ Physics ║       Penguin ║
╚═════════╩═══════╩════════════════════════╩══════════╩═════════╩═══════════════╝

现在,我想有这个选择:

╔══════════════╦═══════╦════════════════════════╦══════════╦═════════╦═══════════════╗
║ book_copy_id ║ title ║         authors        ║ language ║ subject ║   publisher   ║
╠══════════════╬═══════╬════════════════════════╬══════════╬═════════╬═══════════════╣
║            1 ║     A ║ Joe Schmoe, John Smith ║  English ║ History ║ Berkley Books ║
║            2 ║     A ║ Joe Schmoe, John Smith ║  English ║ History ║ Berkley Books ║
║            3 ║     A ║ Joe Schmoe, John Smith ║  English ║ History ║ Berkley Books ║
║            4 ║     B ║             John Smith ║   German ║ Physics ║       Penguin ║
║            5 ║     B ║             John Smith ║   German ║ Physics ║       Penguin ║
╚══════════════╩═══════╩════════════════════════╩══════════╩═════════╩═══════════════╝

我也有这两个表:

SELECT student_id, first_name, last_name FROM student;
╔════════════╦════════════╦═══════════╗
║ student_id ║ first_name ║ last_name ║
╠════════════╬════════════╬═══════════╣
║         81 ║        Bob ║     Dylan ║
║         82 ║        Jim ║    Carrey ║
╚════════════╩════════════╩═══════════╝

SELECT student_id, book_copy_id FROM loan;
╔════════════╦══════════════╗
║ student_id ║ book_copy_id ║
╠════════════╬══════════════╣
║         81 ║            1 ║
║         81 ║            4 ║
║         82 ║            5 ║
╚════════════╩══════════════╝

我需要编写一个产生这个选择的查询:

-- 'a' stands for 'the quantity of book copies that are available for a loan'
-- 't' stands for 'the total quantity of book copies'
╔═══╦═══╦═══════╦════════════════════════╦══════════╦═════════╦═══════════════╗
║ a ║ t ║ title ║         authors        ║ language ║ subject ║ publisher     ║
╠═══╬═══╬═══════╬════════════════════════╬══════════╬═════════╬═══════════════╣
║ 2 ║ 3 ║     A ║ Joe Schmoe, John Smith ║  English ║ History ║ Berkley Books ║
║ 0 ║ 2 ║     B ║             John Smith ║   German ║ Physics ║       Penguin ║
╚═══╩═══╩═══════╩════════════════════════╩══════════╩═════════╩═══════════════╝

我希望我已经非常明确地用图表概述了它。请把这两个问题的问题写下来。

3 个答案:

答案 0 :(得分:1)

您需要加入book_copy并更改group by条件。这解决了您的第一个问题:

SELECT bc.book_copy_id,
       b.title,
       GROUP_CONCAT(CONCAT_WS(' ', a.last_name,
                                   a.first_name)
                              ORDER BY a.last_name
                              SEPARATOR ', ') AS authors,
       l.language,
       s.subject,
       p.publisher
FROM   book AS b
       LEFT JOIN book_author AS ba
              ON b.book_id = ba.book_id
       LEFT JOIN author AS a
              ON ba.author_id = a.author_id
       LEFT JOIN language AS l
              ON b.language_id = l.language_id
       LEFT JOIN subject AS s
              ON b.subject_id = s.subject_id
       LEFT JOIN publisher AS p
              ON b.publisher_id = p.publisher_id
       left join book_copy bc
              on b.book_id = bc.book_id
GROUP BY bc.book_copy_id ASC;

答案 1 :(得分:0)

看起来我解决了第一个问题。请看看它是否合法(但感觉它完美无缺):

SELECT bc.book_copy_id,
       subquery.title,
       subquery.authors,
       subquery.subject,
       subquery.language,
       subquery.publisher
FROM   book_copy AS bc
       LEFT JOIN (SELECT b.book_id,
                         b.title,
                         GROUP_CONCAT(CONCAT_WS(' ', a.last_name,
                                                     a.first_name)
                                                ORDER BY a.last_name
                                                SEPARATOR ', ') AS authors,
                         l.language,
                         s.subject,
                         p.publisher
                  FROM   book AS b
                         LEFT JOIN book_author AS ba
                                ON b.book_id = ba.book_id
                         LEFT JOIN author AS a
                                ON ba.author_id = a.author_id
                         LEFT JOIN language AS l
                                ON b.language_id = l.language_id
                         LEFT JOIN subject AS s
                                ON b.subject_id = s.subject_id
                         LEFT JOIN publisher AS p
                                ON b.publisher_id = p.publisher_id
                  GROUP BY b.title) AS subquery
              ON bc.book_id = subquery.book_id
ORDER BY subquery.title

现在我已经完成了第二个问题。这是解决方案:

SELECT subquery.book_id,
      (COUNT(bc.book_copy_id) - (SELECT COUNT(l.book_copy_id)
                                 FROM   loan AS l
                                 WHERE  l.checked_in IS NULL AND
                                        l.book_copy_id IN (SELECT bc.book_copy_id
                                                           FROM   book_copy AS bc
                                                           WHERE  bc.book_id = subquery.book_id))) AS available,
       COUNT(bc.book_copy_id) AS total,
       subquery.title,
       subquery.authors,
       subquery.subject,
       subquery.language,
       subquery.publisher
FROM   book_copy AS bc
       LEFT JOIN (SELECT b.book_id,
                         b.title,
                         GROUP_CONCAT(CONCAT_WS(' ', a.last_name,
                                                     a.first_name)
                                                ORDER BY a.last_name
                                                SEPARATOR ', ') AS authors,
                         l.language,
                         s.subject,
                         p.publisher
                  FROM   book AS b
                         LEFT JOIN book_author AS ba
                                ON b.book_id = ba.book_id
                         LEFT JOIN author AS a
                                ON ba.author_id = a.author_id
                         LEFT JOIN language AS l
                                ON b.language_id = l.language_id
                         LEFT JOIN subject AS s
                                ON b.subject_id = s.subject_id
                         LEFT JOIN publisher AS p
                                ON b.publisher_id = p.publisher_id
                  GROUP BY b.title) AS subquery
              ON bc.book_id = subquery.book_id
GROUP BY subquery.book_id
ORDER BY subquery.title;

答案 2 :(得分:0)

这应该可以解决问题,但不确定它是如何有效的。

请注意,我将GROUP BY更改为book_id而不是title。如果两本书具有相同的标题,它们仍然是不同的书籍(不确定是否会发生这种情况)。

SELECT COUNT(DISTINCT bc.book_copy_id) - COUNT(DISTINCT lo.book_copy_id) AS a,
   COUNT(DISTINCT bc.book_copy_id) AS t,
   b.book_id,
   b.title,
   GROUP_CONCAT(DISTINCT CONCAT_WS(' ', a.last_name, a.first_name) ORDER BY a.last_name SEPARATOR ', ') AS authors,
   l.language,
   s.subject,
   p.publisher
FROM   book AS b
LEFT JOIN book_author AS ba ON b.book_id = ba.book_id
LEFT JOIN author AS a ON ba.author_id = a.author_id
LEFT JOIN language AS l ON b.language_id = l.language_id
LEFT JOIN subject AS s ON b.subject_id = s.subject_id
LEFT JOIN publisher AS p ON b.publisher_id = p.publisher_id
LEFT JOIN book_copy AS bc ON (bc.book_id = b.book_id)
LEFT JOIN loan AS lo ON (lo.book_copy_id = bc.book_copy_id)
GROUP BY b.book_id;

- 编辑

请注意,GROUP_CONCAT中有DISTINCT。如果两位作者具有相同的名称,则只会列出一次。不确定这是否重要。