2011-04-19 67 views
4

说我有2个表,一个叫做类别,一个叫做cat_pages。MYSQL加入唯一的结果行

类别表具有列ID,标题和时间戳。例如:

CREATE TABLE categories (
    id INT UNSIGNED PRIMARY KEY, 
    title VARCHAR(32), 
    `timestamp` TIMESTAMP, 
    INDEX (title) 
) Engine=InnoDB; 

的cat_pages有2列,CAT_ID和PAGE_ID:

CREATE TABLE cat_pages (
    cat_id INT UNSIGNED 
     REFERENCES categories (id) 
     ON DELETE CASCADE ON UPDATE CASCADE, 
    page_id INT UNSIGNED 
     REFERENCES pages (id) 
     ON DELETE CASCADE ON UPDATE CASCADE, 
    UNIQUE INDEX (cat_id, page_id), 
    INDEX (page_id, cat_id), 
) Engine=InnoDB; 

我想加盟与该ID的cat_pages表分类表,这样

  1. 仅检索category_pages表中具有id的类别
  2. 每个类别仅在结果集中显示一次

查询:

SELECT * FROM categories as c 
    LEFT JOIN cat_pages as p ON c.id = p.cat_id 

产生具有类别重复多次(因为有在cat_pages表多个匹配的结果集。我需要什么才能让每个类别只显示一次,而如果cat_pages表格中没有匹配,则根本不显示?

+0

从你的查询中左键落地实现第一点 – Dalen 2011-04-19 08:05:39

+0

代码为王。描述表的最好方法是给出表创建语句,以及样本数据的'INSERT'语句。你提供的'SELECT'查询在描述你想要的内容时非常有帮助。 – outis 2011-04-19 08:20:22

回答

9

如果您不希望类别不在cat_pages中,请勿使用左连接;使用内部连接。左连接包括左表中的每一行,即使右表中没有匹配的行(缺少的字段为NULL值)。右连接类似,但包含右表中的所有行。一个外部联接包括左右表中的所有行,它们将具有匹配项的行连接起来,并将没有匹配空值的行连接起来。相反,内部连接只包含匹配的行。换句话说,左右连接是一个内连接;他们的联盟是一个外部联盟。 Jeff Atwood发布了一些不错的Venn diagrams describing joins,但应该注意的是,圆圈中的集合不是左右表格的恰当位置,而是左右表格的左右连接的结果。

为了获得不同的行,你可以使用一个DISTINCT修改:

SELECT DISTINCT c.* 
    FROM categories AS c 
    INNER JOIN cat_pages AS cp ON c.id = cp.cat_id 

至于SELECT * ...,请参阅“What is the reason not to use select *?

以获得不同行的另一种方法是使用一个EXISTS条款或IN运算符,但加入可能更高性能(尽管只有EXPLAIN会告诉你一定)。只要确保你有适当的指数设置。

+0

很好的回答,DISTINCT正是我所期待的......我不知道为什么我没有进行内部连接。感谢您选择*的人。 – tgriesser 2011-04-19 08:19:39

-2

为什么不使用Inner Join?

SELECT * FROM categories as c INNER JOIN cat_pages as p ON c.id = p.cat_id 

或者

SELECT * FROM categories as c LEFT JOIN cat_pages as p ON c.id = p.cat_id WHERE p.cat_id IS NOT NULL 

左连接左表中选择所有和比赛上右表。