【问题标题】:Mysql inner join from two or more variables?来自两个或多个变量的Mysql内部连接?
【发布时间】:2012-03-22 05:04:24
【问题描述】:

我有一张桌子,比如:BOOKS

+------+-------------------+---------------+
| id   |  book_title       |  author       |
+------+-------------------+---------------+
| 1    |  learning mysql   |  1234 12      |
+------+-------------------+---------------+
| 2    |  learning php     |  125 50       |
+------+-------------------+---------------+

我想要一个来自 BOOKS 和 AUTHOR 的VIEW:

+------+-------------------+  
| id   |  author           |
+------+-------------------+
| 12   |  JOHN             |
+------+-------------------+
| 50   |  PAUL             |
+------+-------------------+
| 125  |  CHRISTOPHER      |
+------+-------------------+
| 1234 |  PATRICK          |
+------+-------------------+

这样我就可以有一个视图,它应该类似于下面的表格,但应该显示而不是来自 tabel AUTHOR 的作者 ID 作者姓名。

+------+-------------------+-----------------------------------+
| id   |  book_title       |  author                           |
+------+-------------------+-----------------------------------+
| 1    |  learning mysql   |  PATRICK                          |
+------+-------------------+-----------------------------------+
| 1    |  learning mysql   |  CHRISTOPHER                      |
+------+-------------------+-----------------------------------+
| 2    |  learning php     |  JOHN                             |
+------+-------------------+-----------------------------------+
| 2    |  learning php     |  PAUL                             |
+------+-------------------+-----------------------------------+

【问题讨论】:

  • 您应该规范化您的数据库,即拥有一个将 book_ids 与 author_ids 匹配的表。您肯定会在单列中遇到多个值的问题

标签: mysql inner-join


【解决方案1】:

您的数据库设计错误。 books.author 应该是 INT 并包含 author.id 的外键。表author 应包含name VARCHAR(255)(或引用author_name 的两列,我仍然不确定您是否有两个作者或者您将姓名分成2 个条目)。

所以正确的设计应该是:

BOOKS (
  id INT,
  book_title VARCHAR(255),
  author INT, -- only if each book has just one author
  PRIMARY KEY (id)
)

AUTHOR (
  id INT,
  name VARCHAR(255),
  first_name_id INT, -- If you want to split names into more columns
  PRIMARY KEY (id)
)

-- If you need more authors for one book
-- you maybe should keep original (primary) author id
BOOK_AUTHOR (
  book_id INT,
  author_id INT,
  PRIMARY KEY (book_id, author_id)
);

您可以选择以下数据:

SELECT BOOKS.id, BOOKS.book_title, AUTHOR.name AS author
FROM BOOKS
-- Study difference between left and inner joins
INNER JOIN AUTHOR on AUTHOR.id = BOOKS.author

如果您需要为一本书添加更多作者:

SELECT BOOKS.id, BOOKS.book_title, AUTHOR.name AS author
FROM BOOKS
LEFT JOIN BOOK_AUTHOR on BOOK_AUTHOR.book_id = BOOKS.id
LEFT JOIN AUTHOR on AUTHOR.id = BOOK_AUTHOR.author_id

您可能需要将作者输出为Wolfgang Goethe; Oscar Wilde,而不是使用GROUP_CONCAT:

SELECT BOOKS.id, BOOKS.book_title,
       GROUP_CONCAT( AUTHOR.name SEPARATOR '; ') AS author
FROM BOOKS
LEFT JOIN BOOK_AUTHOR on BOOK_AUTHOR.book_id = BOOKS.id
LEFT JOIN AUTHOR on AUTHOR.id = BOOK_AUTHOR.author_id
GROUP BY BOOKS.id

【讨论】:

  • 我有两位作者,但问题是有时有超过 20 位作者,这是一个在线文章社区。​​span>
  • @drake 所以我希望你理解答案的第二部分和表格BOOK_AUTHOR 如果没有,请随时提问。
  • 很好的详细响应,但 BOOK_AUTHOR 主键应该是 (book_id, author_id) 而不是多余的代理键。
【解决方案2】:

正如 cmets 中的 knittl 注释,您绝对应该修复您的数据库设计。也就是说,这是使用现有架构的“蛮力和无知”解决方案:

CREATE VIEW book_author (id, book_title, author)
AS SELECT book.id, book.book_title, author.author
FROM book
  JOIN author ON FIND_IN_SET(author.id, REPLACE(book.author, ' ', ',')) > 0

但这将是一个非常缓慢和丑陋的解决方案,即使它有效。一个更好的解决方案是去掉 book 表中的 author 列,而是添加一个这样的链接表:

CREATE TABLE book_author (
  book INTEGER NOT NULL,
  author INTEGER NOT NULL,
  PRIMARY KEY (book, author),
  UNIQUE KEY (author, book)   /* for "all books by author X" queries */
)

(与 Vyktor 不同,I don't feel that adding extra ID columns to simple link tables is a good idea。该表中已经有一个非常好的自然主键 - 它不需要代理键。)

然后您可以更轻松有效地创建视图:

CREATE VIEW book_author (id, book_title, author)
AS SELECT book.id, book.book_title, author.author
FROM book
  JOIN book_author ON book_author.book = book.id
  JOIN author ON book_author.author = author.id

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 2012-12-09
    相关资源
    最近更新 更多